带Ada驱动程序库的microbit上的Ada i2c演示?

带Ada驱动程序库的microbit上的Ada i2c演示?,ada,bbc-microbit,Ada,Bbc Microbit,概述: 我正试图使用Ada驱动程序库用Ada编写一个microbit,但我不知道如何使用i2c函数与另一个芯片建立通信。我想建立一个简单的演示,这样我就可以了解发生了什么,因为Ada驱动程序库的components目录中的演示已经超出了我的理解范围(我对Ada也很陌生,这对我没什么帮助) Ada驱动程序库中最简单的i2c演示似乎是AK8963三轴罗盘(位于/components/src/motion/AK8963/)。但这仍然困扰着我,我没有芯片来运行和调试代码 以下是我尝试过的: 我用ardu

概述: 我正试图使用Ada驱动程序库用Ada编写一个microbit,但我不知道如何使用i2c函数与另一个芯片建立通信。我想建立一个简单的演示,这样我就可以了解发生了什么,因为Ada驱动程序库的components目录中的演示已经超出了我的理解范围(我对Ada也很陌生,这对我没什么帮助)

Ada驱动程序库中最简单的i2c演示似乎是AK8963三轴罗盘(位于/components/src/motion/AK8963/)。但这仍然困扰着我,我没有芯片来运行和调试代码

以下是我尝试过的: 我用arduinos创建了两个不同的演示。在这两个演示中,发射机发送一个“A”和一个“B”,一直发送到“Z”,然后循环回“A”。在第一个演示中,主机每500毫秒发送下一个字符,从机接收。在第二个演示中,主机每隔500毫秒请求下一个字符,从机将其发送


我的演示是根据找到的arduino Wire示例改编的。

我还无法测试下面的代码,但它至少可以给您一些指导。请注意,micro:bit充当主控。我不认为micro:bit可以充当I2C总线上的从机(但我可能错了)。还请注意,您可能必须更改项目文件中的
microbitzfp.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
  }
}
/*
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);
}
--  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;
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;
以下是完整的Ada项目文件:

/*
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
  }
}
/*
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);
}
--  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;
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;
提示:

/*
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
  }
}
/*
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);
}
--  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;
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地址偏移量(在我的例子中,Arduino上Ada=8中的16)。请参阅上述从属传输arduino代码注释中的说明。我花了很长时间才弄明白
  • 连接到I2C总线的三个设备不工作,即使其中一个没有通电。我不知道到底发生了什么,但我怀疑这与说明I2C总线无法将线路拉回到高位的文档有关。一些文档建议在连接到电源电压的两条I2C线路上放置一个电阻器,以便在设备将线路电压拉低后,线路电压恢复到高
  • 使用示波器这项工作会更容易。如果我有一个问题的话,我可以更快地解决这个问题
它会闪烁,但尽管有很多人在摆弄,它还是不工作。如果我在arduino中分配了我的奴隶地址=8,那么在ada中会变成16#08#?如果microbit必须是主程序,这意味着我需要我在arduino上的程序作为从程序。所以它应该看起来像“”(除了我的程序一次发送一个字符),对吗?程序中对Ctrl.Master_Receive()的调用将向从机请求1字节的数据,然后在状态为Ok时显示该字节?ada程序就是这样工作的吗?是的,
16#08#
8
十六进制(以16为基数),也就是
8
十进制(以10为基数)。阿杜伊诺一定是奴隶。但是,请注意,
Ctrl.Master\u Receive
将等待传入字节。它不会发送请求。为此,您需要添加
Ctrl.Master\u Transmit
(参见更新的示例)。最后,原始示例使用默认速度设置400[kbps],您可以在初始化期间更改此设置(有关可用速度,请参见
microbit-i2c.ads
)。请再次注意,我还无法测试它(因为我目前没有Arduino),所以这是一个最大的努力。最后一个注意事项是,程序假设接收实际的(可显示的)ASCII字符(即范围33(!)到126(~)。如果存储在
数据(0)
中的接收字节与可显示字符不对应,则
显示(字符'Val(数据(0))将无效(即不执行任何操作)。