使用 Ada 驱动程序库在 microbit 上进行 Ada i2c 演示?
Ada i2c demo on the microbit with the Ada Drivers Library?
概览:
我正在尝试使用 Ada 驱动程序库使用 Ada 对 microbit 进行编程,但我不明白如何使用 i2c 函数与另一个芯片建立通信。我想建立一个简单的演示,这样我就可以了解发生了什么,因为 Ada 驱动程序库的组件目录中的演示让我头疼(我也是 Ada 的新手,这无济于事)。
Ada 驱动程序库中最简单的 i2c 演示似乎是用于 AK8963 三轴罗盘(位于 /components/src/motion/ak8963/)。但这仍然让我头疼,我没有 运行 的芯片来调试代码。
这是我试过的方法:
我用 arduinos 创建了两个不同的演示。在这两个演示中,发送器发送一个 'A',然后发送一个 'B',一直发送到 'Z',然后循环返回到 'A'。在第一个演示中,主机每 500 毫秒传输下一个字符,从机接收它。在第二个演示中,主机每 500 毫秒请求下一个字符,从机传输它。
我无法测试下面的代码,但它至少应该给你一些指导。请注意 micro:bit 充当主人。我不认为 micro:bit 可以充当 I2C 总线上的从设备(但我在这里可能是错的)。另请注意,您可能必须将路径更改为项目文件中的 microbit_zfp.gpr
。
default.gpr
with "../Ada_Drivers_Library/boards/MicroBit/microbit_zfp.gpr";
project Default is
for Runtime ("ada") use MicroBit_ZFP'Runtime ("Ada");
for Target use "arm-eabi";
for Main use ("main.adb");
for Languages use ("Ada");
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Create_Missing_Dirs use "True";
package Compiler renames MicroBit_ZFP.Compiler;
package Linker is
for Default_Switches ("Ada") use
MicroBit_ZFP.Linker_Switches &
("-Wl,--print-memory-usage",
"-Wl,--gc-sections",
"-U__gnat_irq_trap");
end Linker;
end Default;
main.adb
with MicroBit.Display; use MicroBit.Display;
with MicroBit.Time; use MicroBit.Time;
with MicroBit.I2C; use MicroBit.I2C;
with HAL.I2C; use HAL.I2C;
procedure Main is
begin
MicroBit.I2C.Initialize (S400kbps); -- Change to desired speed.
declare
Ctrl : constant Any_I2C_Port := MicroBit.I2C.Controller;
Addr : constant I2C_Address := 16#08#; -- Change to correct address.
Data : I2C_Data (0 .. 0);
Status : I2C_Status;
begin
loop
-- Data to be send (here: character 'x').
Data (0) := Character'Pos ('x');
-- Display a dot to indicate where we are.
Display ('.');
-- Send 1 byte of data (length of Data array is 1).
Ctrl.Master_Transmit (Addr, Data, Status);
-- Additional status checking could be done here....
-- Display a colon to indicate where we are.
Display (':');
-- Wait for response (1 byte as the length of the Data array is 1).
Ctrl.Master_Receive (Addr, Data, Status);
-- Check status, and display character if OK.
if Status = Ok then
Display (Character'Val (Data (0)));
else
Display ('!');
end if;
-- Take a short nap (time in milliseconds).
Sleep (250);
end loop;
end;
end Main;
我目前对 BBC micro:bit 和 i2c 感兴趣并试用了该程序,之前已经成功构建和上传了一个程序。使用这两个文件构建应该更容易,但仍然无法构建,正在与 GPS 斗争......我会尽快再试......
我想通了。
让我们从两个Arduino程序开始,来证明Arduino代码可以工作。
Arduino 从机传输:
/*
Sends the next letter of the alphabet with each
request for data from master.
Watch the serial monitor to see what's happening.
*/
#include <avr/wdt.h>
#include <Wire.h>
// A note about I2C addresses.
// The Ada program is looking for the slave on address 16
// but this code says the slave is on 8.
// What's happening? As best as I can tell it works
// like this:
// 16 in binary is 10000. But arduino strips the read/write bit
// (which is the last bit) off of the address so it becomes
// 1000 in binary. And 1000 in binary is 8.
const int SLAVE_ADDRESS = 8;
byte letter = 65; // letter A
unsigned long counter = 0;
void setup()
{
wdt_reset();
wdt_enable(WDTO_8S);
Serial.begin(9600);
Serial.println("beginning");
Wire.begin(SLAVE_ADDRESS); // join i2c bus
Wire.onRequest(requestEvent); // register event
}
void loop()
{
wdt_reset();
counter++;
if(counter % 1000 == 0)
{
// Display a heart beat so we know the arduino has not hung.
Serial.print("looping: ");
Serial.println(counter);
}
delay(5);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
// send the current letter on I2C
Wire.write(letter);
Serial.print("transmitting: ");
Serial.println(char(letter));
letter++;
if(letter > 90) // if greater than Z
{
letter = 65; // reset to A
}
}
Arduino Master 接收:
/*
Requests a character from the slave every 500 ms and prints it
to the serial monitor.
*/
#include <avr/wdt.h>
#include <Wire.h>
const int SLAVE_ADDRESS = 8;
void setup()
{
wdt_reset();
wdt_enable(WDTO_8S);
Wire.begin(); // join i2c bus
Serial.begin(9600);
}
void loop()
{
// reset the watchdog timer
wdt_reset();
// request one byte from the slave
Wire.requestFrom(SLAVE_ADDRESS, 1);
while(Wire.available()) // slave may send less than requested
{
// receive a byte as character
char c = Wire.read();
Serial.println(c);
}
delay(500);
}
这两个Arduino草图会愉快地传递一整天的字符。现在用下面的 Ada 版本替换 Arduino 主接收器并物理断开 Arduino 主接收器。
Ada 主接收器 (main.abd):
-- Request a character from the I2C slave and
-- display it on the 5x5 display in a loop.
with HAL.I2C; use HAL.I2C;
with MicroBit.Display; use MicroBit.Display;
with MicroBit.I2C;
with MicroBit.Time;
procedure Main is
Ctrl : constant Any_I2C_Port := MicroBit.I2C.Controller;
Addr : constant I2C_Address := 16;
Data : I2C_Data (0 .. 0);
Status : I2C_Status;
begin
MicroBit.I2C.Initialize (MicroBit.I2C.S100kbps);
if MicroBit.I2C.Initialized then
-- Successfully initialized I2C
Display ('I');
else
-- Error initializing I2C
Display ('E');
end if;
MicroBit.Time.Delay_Ms (2000);
MicroBit.Display.Clear;
loop
-- Request a character
Ctrl.Master_Receive (Addr => Addr, Data => Data, Status => Status);
-- Display the character or the error
if Status = Ok then
Display (Character'Val (Data (0)));
else
MicroBit.Display.Display (Status'Image);
end if;
-- Give the user time to read the display
MicroBit.Time.Delay_Ms (1000);
MicroBit.Display.Clear;
MicroBit.Time.Delay_Ms (250);
end loop;
end Main;
这里是 Ada 项目文件的完整性:
with "..\..\Ada_Drivers_Library\boards\MicroBit\microbit_zfp.gpr";
project I2C_Master_Receive_Demo is
for Runtime ("ada") use Microbit_Zfp'Runtime ("Ada");
for Target use "arm-eabi";
for Main use ("main.adb");
for Languages use ("Ada");
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Create_Missing_Dirs use "True";
package Compiler renames Microbit_Zfp.Compiler;
package Linker is
for Default_Switches ("ada") use Microbit_Zfp.Linker_Switches & ("-Wl,--print-memory-usage", "-Wl,--gc-sections", "-U__gnat_irq_trap");
end Linker;
package Ide is
for Program_Host use ":1234";
for Communication_Protocol use "remote";
for Connection_Tool use "pyocd";
end Ide;
end I2C_Master_Receive_Demo;
提示:
- 您需要观察 I2C 地址偏移量(在我的例子中,Ada 中的 16 = Arduino 中的 8)。见上面slave transmit arduino代码注释中的解释。我花了很长时间才弄明白。
- 连接到 I2C 总线的三个设备都无法正常工作,即使其中一个未通电。我不知道那里到底发生了什么,但我怀疑它与说明 I2C 总线无法将其线路拉回高电平的文档有关。一些文档建议在连接到源电压的两条 I2C 线路上放置一个电阻器,以便在设备将它们拉低后线路电压 return 变为高电平。
- 如果使用示波器,这项工作会更容易。如果我有一个问题,我本可以更快地解决这个问题。
概览: 我正在尝试使用 Ada 驱动程序库使用 Ada 对 microbit 进行编程,但我不明白如何使用 i2c 函数与另一个芯片建立通信。我想建立一个简单的演示,这样我就可以了解发生了什么,因为 Ada 驱动程序库的组件目录中的演示让我头疼(我也是 Ada 的新手,这无济于事)。
Ada 驱动程序库中最简单的 i2c 演示似乎是用于 AK8963 三轴罗盘(位于 /components/src/motion/ak8963/)。但这仍然让我头疼,我没有 运行 的芯片来调试代码。
这是我试过的方法: 我用 arduinos 创建了两个不同的演示。在这两个演示中,发送器发送一个 'A',然后发送一个 'B',一直发送到 'Z',然后循环返回到 'A'。在第一个演示中,主机每 500 毫秒传输下一个字符,从机接收它。在第二个演示中,主机每 500 毫秒请求下一个字符,从机传输它。
我无法测试下面的代码,但它至少应该给你一些指导。请注意 micro:bit 充当主人。我不认为 micro:bit 可以充当 I2C 总线上的从设备(但我在这里可能是错的)。另请注意,您可能必须将路径更改为项目文件中的 microbit_zfp.gpr
。
default.gpr
with "../Ada_Drivers_Library/boards/MicroBit/microbit_zfp.gpr";
project Default is
for Runtime ("ada") use MicroBit_ZFP'Runtime ("Ada");
for Target use "arm-eabi";
for Main use ("main.adb");
for Languages use ("Ada");
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Create_Missing_Dirs use "True";
package Compiler renames MicroBit_ZFP.Compiler;
package Linker is
for Default_Switches ("Ada") use
MicroBit_ZFP.Linker_Switches &
("-Wl,--print-memory-usage",
"-Wl,--gc-sections",
"-U__gnat_irq_trap");
end Linker;
end Default;
main.adb
with MicroBit.Display; use MicroBit.Display;
with MicroBit.Time; use MicroBit.Time;
with MicroBit.I2C; use MicroBit.I2C;
with HAL.I2C; use HAL.I2C;
procedure Main is
begin
MicroBit.I2C.Initialize (S400kbps); -- Change to desired speed.
declare
Ctrl : constant Any_I2C_Port := MicroBit.I2C.Controller;
Addr : constant I2C_Address := 16#08#; -- Change to correct address.
Data : I2C_Data (0 .. 0);
Status : I2C_Status;
begin
loop
-- Data to be send (here: character 'x').
Data (0) := Character'Pos ('x');
-- Display a dot to indicate where we are.
Display ('.');
-- Send 1 byte of data (length of Data array is 1).
Ctrl.Master_Transmit (Addr, Data, Status);
-- Additional status checking could be done here....
-- Display a colon to indicate where we are.
Display (':');
-- Wait for response (1 byte as the length of the Data array is 1).
Ctrl.Master_Receive (Addr, Data, Status);
-- Check status, and display character if OK.
if Status = Ok then
Display (Character'Val (Data (0)));
else
Display ('!');
end if;
-- Take a short nap (time in milliseconds).
Sleep (250);
end loop;
end;
end Main;
我目前对 BBC micro:bit 和 i2c 感兴趣并试用了该程序,之前已经成功构建和上传了一个程序。使用这两个文件构建应该更容易,但仍然无法构建,正在与 GPS 斗争......我会尽快再试......
我想通了。
让我们从两个Arduino程序开始,来证明Arduino代码可以工作。
Arduino 从机传输:
/*
Sends the next letter of the alphabet with each
request for data from master.
Watch the serial monitor to see what's happening.
*/
#include <avr/wdt.h>
#include <Wire.h>
// A note about I2C addresses.
// The Ada program is looking for the slave on address 16
// but this code says the slave is on 8.
// What's happening? As best as I can tell it works
// like this:
// 16 in binary is 10000. But arduino strips the read/write bit
// (which is the last bit) off of the address so it becomes
// 1000 in binary. And 1000 in binary is 8.
const int SLAVE_ADDRESS = 8;
byte letter = 65; // letter A
unsigned long counter = 0;
void setup()
{
wdt_reset();
wdt_enable(WDTO_8S);
Serial.begin(9600);
Serial.println("beginning");
Wire.begin(SLAVE_ADDRESS); // join i2c bus
Wire.onRequest(requestEvent); // register event
}
void loop()
{
wdt_reset();
counter++;
if(counter % 1000 == 0)
{
// Display a heart beat so we know the arduino has not hung.
Serial.print("looping: ");
Serial.println(counter);
}
delay(5);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
// send the current letter on I2C
Wire.write(letter);
Serial.print("transmitting: ");
Serial.println(char(letter));
letter++;
if(letter > 90) // if greater than Z
{
letter = 65; // reset to A
}
}
Arduino Master 接收:
/*
Requests a character from the slave every 500 ms and prints it
to the serial monitor.
*/
#include <avr/wdt.h>
#include <Wire.h>
const int SLAVE_ADDRESS = 8;
void setup()
{
wdt_reset();
wdt_enable(WDTO_8S);
Wire.begin(); // join i2c bus
Serial.begin(9600);
}
void loop()
{
// reset the watchdog timer
wdt_reset();
// request one byte from the slave
Wire.requestFrom(SLAVE_ADDRESS, 1);
while(Wire.available()) // slave may send less than requested
{
// receive a byte as character
char c = Wire.read();
Serial.println(c);
}
delay(500);
}
这两个Arduino草图会愉快地传递一整天的字符。现在用下面的 Ada 版本替换 Arduino 主接收器并物理断开 Arduino 主接收器。
Ada 主接收器 (main.abd):
-- Request a character from the I2C slave and
-- display it on the 5x5 display in a loop.
with HAL.I2C; use HAL.I2C;
with MicroBit.Display; use MicroBit.Display;
with MicroBit.I2C;
with MicroBit.Time;
procedure Main is
Ctrl : constant Any_I2C_Port := MicroBit.I2C.Controller;
Addr : constant I2C_Address := 16;
Data : I2C_Data (0 .. 0);
Status : I2C_Status;
begin
MicroBit.I2C.Initialize (MicroBit.I2C.S100kbps);
if MicroBit.I2C.Initialized then
-- Successfully initialized I2C
Display ('I');
else
-- Error initializing I2C
Display ('E');
end if;
MicroBit.Time.Delay_Ms (2000);
MicroBit.Display.Clear;
loop
-- Request a character
Ctrl.Master_Receive (Addr => Addr, Data => Data, Status => Status);
-- Display the character or the error
if Status = Ok then
Display (Character'Val (Data (0)));
else
MicroBit.Display.Display (Status'Image);
end if;
-- Give the user time to read the display
MicroBit.Time.Delay_Ms (1000);
MicroBit.Display.Clear;
MicroBit.Time.Delay_Ms (250);
end loop;
end Main;
这里是 Ada 项目文件的完整性:
with "..\..\Ada_Drivers_Library\boards\MicroBit\microbit_zfp.gpr";
project I2C_Master_Receive_Demo is
for Runtime ("ada") use Microbit_Zfp'Runtime ("Ada");
for Target use "arm-eabi";
for Main use ("main.adb");
for Languages use ("Ada");
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Create_Missing_Dirs use "True";
package Compiler renames Microbit_Zfp.Compiler;
package Linker is
for Default_Switches ("ada") use Microbit_Zfp.Linker_Switches & ("-Wl,--print-memory-usage", "-Wl,--gc-sections", "-U__gnat_irq_trap");
end Linker;
package Ide is
for Program_Host use ":1234";
for Communication_Protocol use "remote";
for Connection_Tool use "pyocd";
end Ide;
end I2C_Master_Receive_Demo;
提示:
- 您需要观察 I2C 地址偏移量(在我的例子中,Ada 中的 16 = Arduino 中的 8)。见上面slave transmit arduino代码注释中的解释。我花了很长时间才弄明白。
- 连接到 I2C 总线的三个设备都无法正常工作,即使其中一个未通电。我不知道那里到底发生了什么,但我怀疑它与说明 I2C 总线无法将其线路拉回高电平的文档有关。一些文档建议在连接到源电压的两条 I2C 线路上放置一个电阻器,以便在设备将它们拉低后线路电压 return 变为高电平。
- 如果使用示波器,这项工作会更容易。如果我有一个问题,我本可以更快地解决这个问题。