【问题标题】:Ada i2c demo on the microbit with the Ada Drivers Library?使用 Ada 驱动程序库在 microbit 上进行 Ada i2c 演示?
【发布时间】:2019-10-08 20:04:45
【问题描述】:

概述: 我正在尝试使用 Ada Drivers Library 使用 Ada 对 microbit 进行编程,但我不明白如何使用 i2c 功能与另一个芯片建立通信。我想建立一个简单的演示,这样我就可以理解发生了什么,因为 Ada 驱动程序库的组件目录中的演示超出了我的想象(我对 Ada 也很陌生,这无济于事)。

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

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

我的演示改编自 herehere 的 arduino Wire 示例。

【问题讨论】:

    标签: ada bbc-microbit


    【解决方案1】:

    我想通了。

    让我们从两个 Arduino 程序开始,证明 Arduino 代码有效。

    Arduino Slave 传输:

    /*
    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)。请参阅上面从机传输 arduino 代码的 cmets 中的说明。我花了很长时间才弄明白。
    • 连接到 I2C 总线的三台设备无法正常工作,即使其中一台没有通电。我不确切知道那里发生了什么,但我怀疑它与说明 I2C 总线无法将其线路拉回 HIGH 的文档有关。一些文档建议在连接到源电压的两条 I2C 线路上放置一个电阻器,以便线路电压在设备将其拉低后返回到高电平。
    • 使用示波器会更容易完成这项工作。如果我有一个问题,我可以更快地解决这个问题。

    【讨论】:

      【解决方案2】:

      我无法测试下面的代码,但它至少应该给你一些指导。请注意,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;
      

      ma​​in.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;
      

      【讨论】:

      • 它会闪烁,但尽管进行了很多摆弄,但它仍然无法正常工作。如果我在我的 arduino 中分配了我的从地址 = 8,那在 ada 中会变成 16#08# 吗?如果 microbit 必须是主机,这意味着我需要 arduino 上的程序作为从机。所以它应该看起来像“Code for Slave Sender - Program for Arduino 2”(除了我的程序一次发送一个字符),对吗?并且在您的程序中调用 Ctrl.Master_Receive() 将要求从机提供 1 个字节的数据,然后在 Status = Ok 时显示该字节?你的 ada 程序就是这样工作的吗?
      • 是的,16#08#8 十六进制(基数 16),即 8 十进制(基数 10)。 Arduino 必须是奴隶。但是请注意,Ctrl.Master_Receive 将等待传入字节。它不会发送请求。为此,您需要添加 Ctrl.Master_Transmit(请参阅更新的示例)。最后,原始示例使用 400 [kbps] 的默认速度设置,您可以在初始化期间更改此设置(请参阅microbit-i2c.ads 了解可用速度)。请再次注意,我无法对其进行测试(因为我目前没有 Arduino),所以这是最好的努力。
      • 最后一点,程序假定接收一个实际的(可显示的)ASCII 字符(即范围 33 (!) 到 126 (~))。如果接收到的存储在Data (0) 中的字节与可显示字符不对应,则Display (Character'Val (Data (0))); 将不起作用(即什么也不做)。
      【解决方案3】:

      我目前对 BBC micro:bit 和 i2c 感兴趣,并尝试了该程序,之前有一个程序可以成功构建和上传。使用这两个文件构建应该更容易,但仍然无法构建,与 GPS 苦苦挣扎......我很快会再试一次......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-31
        • 2012-02-17
        • 1970-01-01
        相关资源
        最近更新 更多