搜索
bottom↓
回复: 3

请教马老师:关于马老师书上SPI的例子

[复制链接]

出0入0汤圆

发表于 2008-7-11 21:42:12 | 显示全部楼层 |阅读模式
在书443页,关于SPI的例子,在void putSPIchar(unsigned char c)中,有一语句
   if(tx_counter||((SPSR&0x80)==0))    感觉这句有问题,因为SPI接口在空闲时和在发送时 (SPSR&0x80)==0,这句都成立,所以发送数据时,预发送的数据都进入了发送缓冲区,在SPI空闲时或第一次发送时,将不能写SPDR启动SPI,因为程序中要在中断时写SPDR.没有写SPDR启动SPI,将不会进入中断。
请马老师在看一下程序,是不是有问题,还是我说错了,谢谢

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2008-7-11 23:58:55 | 显示全部楼层
谢谢。我重新仔细参考了手册,是有这样的问题。使用一个标志变量解决这个BUG。

具体代码见如下:

#define SIZE 100
unsigned char SPI_rx_buff[SIZE];
unsigned char SPI_tx_buff[SIZE];
unsigned char rx_wr_index,rx_rd_index,rx_counter,rx_buffer_overflow;
unsigned char tx_wr_index,tx_rd_index,tx_counter;
unsigned char SPI_free;

interrupt [SPI_STC] void spi_isr(void)        // SPI 完成中断服务
{
  SPI_rx_buff[rx_wr_index] = SPDR;                // 从SPI口读出收到的字节放入接收缓冲区
  if (tx_counter)                                // 如果发送缓冲区中有待发的数据
  {
    SPDR = SPI_tx_buff[tx_rd_index];                // 发送1字节数据,
    --tx_counter;                             // 待发送数据个数减1
    if (++tx_rd_index == SIZE) tx_rd_index = 0; // 调整发送缓冲区队列指针
  }
  else SPI_free = 1;                          // 无待发送数据,置SPI空闲

  if (++rx_wr_index == SIZE) rx_wr_index = 0; // 调整接收缓冲区队列指针
  if (++rx_counter == SIZE)
  {
     rx_counter = 0;
     rx_buffer_overflow = 1;                                  // 接收数据溢出
  }
}

unsigned char getSPIchar(void)
{
  unsigned char data;
  while (rx_counter == 0);                                //无接收数据,等待(死循环!)
  data = SPI_rx_buff[rx_rd_index];                        //从接收缓冲区取出一个SPI收到的数据
  if (++rx_rd_index == SIZE) rx_rd_index = 0;         //调整指针
  #asm("cli")
  --rx_counter;
  #asm("sei")
  return data;
}

void putSPIchar(unsigned char c)
{
  while (tx_counter == SIZE);                        // 发送缓冲区满,等待
  #asm("cli")
  if (SPI_free)
  {
    SPDR = c;                                        // SPI口空闲,直接放入SPDR由SPI口发送
    SPI_free = 0;                                        // 置SPI忙
  }
  else
  {                                                                             
    SPI_tx_buffer[tx_wr_index] = c;                        // 将数据放入发送缓冲区排队
    if (++tx_wr_index == SIZE) tx_wr_index = 0;        //调整指针
    ++tx_counter;
  }
  #asm("sei")
}

void spi_init(void)
{
  unsigned char temp;
  DDRB |= 0xB0;        // MISO为输入方式,MOSI,SCK和~SS为输出方式
  PORTB |= 0x40;        // MISO上拉电阻有效
  SPCR = 0xD5;        // SPI允许,主机模式,MSB方式,允许SPI中断,极性方式01,1/16系统时钟频率
  SPSR = 0x00;
  temp = SPSR;
  temp = SPDR;        // 清除SPI中断标志位,使SPI空闲
  SPI_free = 1; // 置SPI空闲
}

void main(void)
{
  unsigned char i;
  #asm("cli")           // 关中断
  spi_init();             // 初始化SPI接口
  #asm("sei")         // 使能中断
  while()
  {
    putSPIchar(i);                // 通过SPI发送1字节
    i++;
    getSPIchar();                // 读取SPI接收的字节
    ………
  }
}

出0入0汤圆

 楼主| 发表于 2008-7-12 19:23:07 | 显示全部楼层
谢谢马老师,这么晚了还在帮忙解答。全局变量SPI_free,是不是应该初始化为1呢

出0入0汤圆

发表于 2008-7-12 19:33:43 | 显示全部楼层
是在void spi_init(void){}中初始化为1的。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-9 18:42

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表