xiezx 发表于 2014-7-29 14:33:17

atmega328p spi通信只能接收到第一位数据

本帖最后由 xiezx 于 2014-7-29 19:12 编辑

测试flash memory at26f004
println() 是串口通信函数

程序如下
unsigned char data;


void spi_initialisation(void)
{
        //设置SCK MOSI SS输出 1
        DDRB &= ~(0x3c);
        DDRB |= 0x2C;
       
        SPCR = 0x50;
println("init finished");
}

void spi_transmit(char data)
{
        SPDR = data;
        while(!(SPSR & (1 << SPIF)));
}

unsigned char spi_receive(void)
{
        while(!(SPSR & (1 << SPIF)));
        return SPDR;
}

void flash_read()
{
println("start read");
        PORTB &= ~(1 << PORTB2);
        spi_transmit(0x03);
println("opcode");
        spi_transmit(0x00);
        spi_transmit(0x00);
        spi_transmit(0x00);
println("address");
        /*for(unsigned char i = 0;i < 8;i++)
        {
                data = spi_receive();
println("data");
        }*/
        data = spi_receive();
println("data");
        data = spi_receive();
println("data");
        data = spi_receive();
println("data");
        data = spi_receive();
println("data");
        PORTB |= 1 << PORTB2;
}


void _flash_text()
{
        spi_initialisation();
        PORTB |= 1 << PORTB2;
        _delay_ms(1000);
       
       
        flash_read();
       
        for(unsigned char i = 0;i < 8;i++)
        {
                print_byte_hex(data);
        }
       
}

由串口通信的结果知道
init finished
start read
opcode
address
data
只能进行完第一次接收
不知道是因为什么
麻烦大伙帮帮想想


下面是一些资料










好吧现在问题解决了
只是在等待中断标志置位之前 加了一句
SPDR = 0X00;
像这样
unsigned char spi_receive(void)
{
        SPDR=0x00;
        while(!(SPSR & (1 << SPIF)));
        return SPDR;
}
就行了
可是为什么呢
这样给SPDR赋值不是会当作数据发送出去吗
有没有人能解释一下

lcw_swust 发表于 2014-7-29 14:56:12

难道是没清标志?
SPIF可能一直有效

alias 发表于 2014-7-29 15:58:24

SPI 没有可能有单独分开的传送或接收程式,因为是同时发生的。传送时你一定也同时接收,关键是你是否对接收来所得的资料住作出处理。

但你必需读取收来的资料,否则SPIF标志一直有效。

alias 发表于 2014-7-29 16:09:39

楼主的 SPI 『接收』程式并没有对 SPDR 写入任意数值,AVR 为主的 SPI,跟本不会产生 SCK,何来接收资料?

xiezx 发表于 2014-7-29 17:12:40

其实是写了内容的呀
void flash_read()
{
println("start read");
        PORTB &= ~(1 << PORTB2);
        spi_transmit(0x03);//<<<<<---------------------------------传送opcode 表示read array
println("opcode");
//<<<<<<<<<<<<<<<<<-----------------------------------------传送3byte的地址字节
        spi_transmit(0x00);
        spi_transmit(0x00);
       
        spi_transmit(0x00);
       
println("address");
        /*for(unsigned char i = 0;i < 8;i++)
        {
                data = spi_receive();
println("data");
        }*/
        data = spi_receive();
println("data");
        data = spi_receive();
println("data");
        data = spi_receive();
println("data");
        data = spi_receive();
println("data");
        PORTB |= 1 << PORTB2;
}

xiezx 发表于 2014-7-29 17:17:35

嗯 楼上说必须读取SPDR的值也读取过了呀
unsigned char spi_receive(void)
{
        while(!(SPSR & (1 << SPIF)));
        return SPDR;//<=======这里╮(╯▽╰)╭
}
这样算读取过了吗
avr的Data sheet里就是这样写的

xiezx 发表于 2014-7-29 17:53:15

alias 发表于 2014-7-29 16:09
楼主的 SPI 『接收』程式并没有对 SPDR 写入任意数值,AVR 为主的 SPI,跟本不会产生 SCK,何来接收资料? ...

而且应该不存在写的同时有数据传进来的情况

xiezx 发表于 2014-7-29 17:55:40

lcw_swust 发表于 2014-7-29 14:56
难道是没清标志?
SPIF可能一直有效

应该不是吧

我也试了一下
好像清没清标志位对结果没什么改变的样子

lcw_swust 发表于 2014-7-29 21:34:23

xiezx 发表于 2014-7-29 17:55
应该不是吧

我也试了一下


这样改一下:
char spi_transmit(char data)
{
      SPDR = data;
      while(!(SPSR & (1 << SPIF)));
        data=SPDR;
        return data;
}
将spi_receive函数去掉,用spi_transmit(0xFF)代替

xiezx 发表于 2014-7-30 11:40:26

嗯 好像这样是可以的
之前也用接收等待前加一句
SPDR = 0X00;
解决了这个问题
非常感谢啊

但是好像又有了新的问题
确实后面的数据能接到了
但是好像和我写进去的数据不一样
换句话说是不是接收到的并不是数据
通信还是没成功啊
页: [1]
查看完整版本: atmega328p spi通信只能接收到第一位数据