发送和接收16位数据寄存器从器件和8位寄存器主器件AVR通过SPI通信

时间:2017-06-28 11:50:06

标签: microcontroller avr atmega atmelstudio

我是Avr编程的初学者,我有一个16位寄存器从器件(存储器芯片),我想通过Atmega328(8位寄存器)在存储器中读写,我知道我必须发送8 x 8位,我已经尝试过编程,但是我无法使用Atmel Studio调试器从我的奴隶那里读取,有人可以给我建议吗?

与我的芯片通信的协议是SPI。

串行通信在芯片的数据表中描述为:

  1. 阅读:
  2. 要从chipi读取必须发送:

    0x03            = 0b00000011:          8 bit  READ command
    0x0000 - 0x07FF = 0bXXXXXAAA AAAAAAAA: 16 bit ADDRESS (5 upper bits don't care)
    

    然后我会收到:

    0x0000 - 0xFFFF = 0bDDDDDDDD DDDDDDDD: 16 bit DATA
    
    1. 写:
    2. 要写入我必须发送的芯片:

      0x02            = 0b00000010:          8 bit  WRITE command
      0x0000 - 0x07FF = 0bXXXXXAAA AAAAAAAA: 16 bit ADDRESS (5 upper bits don't care)
      0x0000 - 0xFFFF = 0bDDDDDDDD DDDDDDDD: 16 bit DATA
      
      1. 内存布局:
      2. 用户存储区从0x0000变为0xA6F。

        1. 使用SPI信息寄存器:
        2. 在串行通信模式下,如果LSI在执行READ / WRITE命令时发生错误,则错误代码将存储在e SPI错误信息寄存器中。

          Bit       15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
          Function  0  0  0  0  0  0  0  0  0  0  0  0  | ERROR* |
          * :  ERROR
          b1000 : Low voltage detection
          b0100 : Write NG
          b0010 : Read NG
          b0001 : NG because RF occurred
          b0000 : Finished successfully
          

          我的SPI init是:

          void spi_init()
          // Initialize pins for spi communication
          {
          
              // set MOSI , select chip SS and SCK Output, all others are outputs
              DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SCK) );/*|(1<<DD_SS))*/
              // set MISO us input 
          
               //Enable SPI, Master, set clock rate
               SPCR = (1<<SPE|(1<<MSTR)| (1<<SPR0)|       // SPI Enable
              (0<<SPIE)|              // SPI Interrupt Enable
              (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
              (1<<MSTR)|              // Master/Slave select
              (0<<SPR1)|(1<<SPR0)|    // SPI Clock Rate
              (1<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
              (1<<CPHA));           // Clock Phase (0:leading / 1:trailing edge sampling)
          
              SPSR = (1<<SPI2X);              // Double Clock Rate
          
          }
          
          void SPI_MasterTransmit(uint16_t cdata){
              SPDR = cdata;  //start transmission 
              while(!(SPSR & (1<<SPIF)));  // wait for transmission complete
          }
           uint16_t SPI_SlaveReceive(void){
               while(!(SPSR & (1<<SPIF)));  //wait for reception complete     
               return (SPDR);             //return Data Register
           }
          

          读:

          uint16_t read_SPI( uint16_t address){
              uint16_t datar; 
                  Slave_select;   
              // charger les données inf au buffer 
                  SPDR = uint16_t( address & 0xFF);
                  //attente lors de la premiere transmission 
                  while(!(SPSR & (1<<SPIF) ));
                  // premier octet est reçu 
                  datar = SPDR;
          
                  // charger les données sup au buffer 
                  SPDR = uint16_t ((address >> 8) & 0xFF);
                  //attente de la seconde tr 
                  while(!(SPSR & (1<<SPIF) ));
                  // seceond octet est reçu 
                  datar = datar | ((uint16_t) (SPDR) << 8);
                 Slave_deselect;
                  return datar; 
          
          }
          

          void write_SPI (uint16_t address, uint16_t data){
              Slave_select;
              SPDR= data; 
              while(!(SPSR & (1<<SPIF)));
              /*data = SPDR;*/ // erase SPDR register 
              Slave_deselect; 
          }
          

1 个答案:

答案 0 :(得分:0)

你永远不会发送命令,只发送地址的低8位。

粗略地说,ATmega侧的引脚设置应如下所示:

PORT? = (1u << MISO) | (1u << MOSI) | (1u << SCK) | (1u << CS);
DDR? = (1u << MOSI) | (1u << CS) | (1u << SCK);
/* pull-up on MISO, init all others idle high/active low */

然后读取函数是这样的:

uint16_t read_SPI( uint16_t address){
    uint16_t res;
    PORT? &= ~(1u << CS); /* assert #CS */
    SPDR = 0x03u; /* READ command */
    while(!(SPSR & (1<<SPIF) ));
    SPDR = (address >> 8) & 0xFFu; /* high-order address bits */
    while(!(SPSR & (1<<SPIF) ));
    SPDR = (address >> 0) & 0xFFu; /* low-order address bits */
    while(!(SPSR & (1<<SPIF) ));
    SPDR = 0xFFu; /* dummy write to clock in high-order data bits */
    while(!(SPSR & (1<<SPIF) ));
    res = SPDR;
    SPDR = 0xFFu; /* dummy write to clock in low-order data bits */
    res <<= 8;
    res = SPDR;
    PORT? |= (1u << CS); /* deassert #CS */
    return res;
}

请注意这是一个非常基本的示例,通常您不希望无限期地阻止微控制器等待SPI状态标志。但是,请考虑将此代码设置为可以可靠地读取和写入EEPROM的位置。然后,您可以添加一些抽象,并使用数据结构和基于中断的SPI例程来处理访问内存。