Ada i2c demo on the microbit with the Ada Drivers Library?
概述:
我正在尝试使用 Ada Drivers Library 使用 Ada 对 microbit 进行编程,但我无法理解如何使用 i2c 功能与另一个芯片建立通信。我想建立一个简单的演示,这样我就可以理解发生了什么,因为 Ada 驱动程序库的组件目录中的演示超出了我的想象(我对 Ada 也很陌生,但这并没有无济于事)。
Ada 驱动程序库中最简单的 i2c 演示似乎适用于 AK8963 三轴罗盘(位于 /components/src/motion/ak8963/)。但这仍然让我头疼,而且我没有芯片来运行和调试代码。
这是我尝试过的:
我用 arduinos 创建了两个不同的演示。在这两个演示中,发射器都发送一个\\'A\\',然后是一个\\'B\\',一直到\\'Z\\',然后循环回到\\'A\\'。在第一个演示中,主机每 500 毫秒发送下一个字符,从机接收它。在第二个演示中,主机每 500 毫秒请求下一个字符,从机发送它。
我的演示改编自此处和此处的 arduino Wire 示例。
我想通了。
让我们从两个 Arduino 程序开始,证明 Arduino 代码有效。
Arduino Slave 传输:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | /* Sends the next letter of the alphabet with each request for data from master. Watch the serial monitor to see what's happening. */ #include #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 接收:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /* Requests a character from the slave every 500 ms and prints it to the serial monitor. */ #include #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):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | -- 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 项目文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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)。请参阅上面从属传输 arduino 代码的注释中的解释。我花了很长时间才弄清楚这一点。
- 连接到 I2C 总线的三个设备没有任何工作,即使其中一个没有通电。我不确切知道那里发生了什么,但我怀疑它与说明 I2C 总线无法将其线路拉回 HIGH 的文档有关。一些文档建议在连接到源电压的两条 I2C 线路上放置一个电阻器,以便线路电压在设备将其拉低后返回到高电平。
- 使用示波器,这项工作会更容易。如果我有一个问题,我可以更快地解决这个问题。
我目前对 BBC micro:bit 和 i2c 感兴趣并尝试了该程序,之前获得了一个成功构建和上传的程序。使用这两个文件构建应该更容易,但仍然无法构建,与 GPS 苦苦挣扎......我很快会再试一次......
我无法测试下面的代码,但它至少应该给你一些方向。请注意,micro:bit 充当主机。我不认为 micro:bit 可以在 I2C 总线上充当从设备(但我在这里可能错了)。另请注意,您可能必须更改项目文件中
default.gpr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 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; |