[Atmel] AVR硬件SPI从机模式调试记录!(MEGA8)

[复制链接]
1449|1
 楼主| 春风的暖暖 发表于 2015-8-31 21:37 | 显示全部楼层 |阅读模式
由于第一次用MEGA8的SPI从模式,程序使用中断模式接收,刚开始spi不能进入中断,网上查资料,
  有网友把MOSI方向设为输出能解决问题,按照此方法果然进入了中断,程序顺利完成并打开看门狗。
  试着把MOSI又改为输入,程序运行正常,有待进一步验证。
uart.h
  1. extern void uart_init(void);
  2. extern void send_char(unsigned char c);
  3. extern void send_string(unsigned char * string , unsigned int strLen);

uart.c
  1.     #include<avr/io.h>
  2.     #include <avr/wdt.h>
  3.     #include<util/delay.h>
  4.     #include<avr/eeprom.h>
  5.     #include<avr/pgmspace.h>
  6.     #include<avr/interrupt.h>
  7.     #include "uart.h"
  8.     /************************************************************
  9.     *   函数名称:void uart_init()
  10.     *   功    能:串口初始化
  11.     *   入口参数:无
  12.     *   出口参数:无
  13.     ************************************************************/
  14.     void uart_init(void)
  15.     {
  16.     UCSRB = 0x00; //disable while setting baud rate
  17.     UCSRA = 0x00;
  18.     UCSRC = (1<<URSEL) | 0x06;//异步,8位数据,无奇偶校验,一个停止位,无倍速
  19.       /*
  20.         UBRRH与UCSRC共用I/O 地址。因此访问该地址时需注意以下问题。
  21.         写访问
  22.         当在该地址执行写访问时, USART 寄存器选择位(URSEL)控制被写入的寄存器。
  23.         若URSEL为0,对UBRRH值更新;若URSEL为1,对UCSRC设置更新
  24.       
  25.         读访问
  26.         对UBRRH 或UCSRC 寄存器的读访问则较为复杂。但在大多数应用中,基本不需要读这些寄存器
  27.       
  28.       
  29.         没有UBRR这个16位寄存器,因为UBRRL(0x09)/UBRRH(0x20)的地址不连续,而且UBRRH跟UCSRC共用地址
  30.       
  31.       
  32.         U2X=0时的公式计算
  33.         UBRRL= (F_CPU/BAUDRATE/16-1)%256;
  34.         UBRRH= (F_CPU/BAUDRATE/16-1)/256;
  35.         U2X=1时的公式计算
  36.         UBRRL= (F_CPU/BAUDRATE/8-1)%256;
  37.         UBRRH= (F_CPU/BAUDRATE/8-1)/256;
  38.     */
  39.     /*------也可根据数据手册的[波特率设置的例子]查得---------*/
  40.     UBRRL = 0x2F;   //9600
  41.     UBRRH = 0x00; //set baud rate hi
  42.     UCSRB = 0x18; //使能接收,使能发送
  43.     }
  44.     /************************************************************
  45.     *   函数名称:void send_char()
  46.     *   功    能:串口发送单字符
  47.     *   入口参数:unsigned char c
  48.     *   出口参数:无
  49.     ************************************************************/
  50.     void send_char(unsigned char c)
  51.     {
  52.     while( !(UCSRA & (1<<UDRE)) );
  53.     UDR=c;
  54.     }
  55.     /************************************************************
  56.     *   函数名称:void send_string()
  57.     *   功    能:串口发送字符串
  58.     *   入口参数:unsigned char * string , unsigned int strLen
  59.     *   出口参数:无
  60.     ************************************************************/
  61.     void send_string(unsigned char * string , unsigned int strLen)
  62.     {
  63.       unsigned int i="0";
  64.       do
  65.        {
  66.     send_char( *(string +i) );
  67.     i++;
  68.        }while( i < strLen );
  69.     }



 楼主| 春风的暖暖 发表于 2015-8-31 21:37 | 显示全部楼层
main.c
  1.     /*****************************************************************************
  2.     *   项    目:  基于科大讯飞XF-S4040语音播放小系统
  3.     *   功    能:   实现SPI转UART(spi从机模式)
  4.     *   目标系统:   ATmega8L-8AU
  5.     *   时    钟:  7.3728MHz
  6.     *   开发软件:   AVR Studio4.14                                             
  7.     *   版    本:   Version 1.0
  8.     *   原版时间:   2009-05-13
  9.     *   修改时间:
  10.     *   说    明:
  11.     *   开发人员:   zjf
  12.     *   说    明:  spi从模式MOSI刚开始设置为输入时未发生spi中断,设置为输出中断发生,有待进一步验证!
  13.                     进一步测试,设置为输入也可以进入中断,奇怪!!!
  14.     *****************************************************************************/
  15.     #include<avr/io.h>
  16.     #include <avr/wdt.h>
  17.     #include<util/delay.h>
  18.     #include<avr/eeprom.h>
  19.     #include<avr/pgmspace.h>
  20.     #include<avr/interrupt.h>
  21.     #include<avr/signal.h>
  22.     #include"uart.h"

  23.     #define CHECK_4040 (PINC&0x02)          //判S4040状态,1=忙,0=就绪
  24.     #define BUSY_4040   (PORTC=PORTC|0x01)  //输出S4040忙信号
  25.     #define READY_4040  (PORTC=PORTC&0xFE)  //输出S4040就绪信号
  26.     /*----------------SPI端口定义-----------------*/
  27.     #define SPI_CS_DDR  DDRB
  28.     #define SPI_CS_PORT PORTB
  29.     #define SPI_CS_BIT  2

  30.     #define SPI_SCK_DDR  DDRB
  31.     #define SPI_SCK_PORT PORTB
  32.     #define SPI_SCK_BIT  5

  33.     #define SPI_MOSI_DDR  DDRB
  34.     #define SPI_MOSI_PORT PORTB
  35.     #define SPI_MOSI_BIT  3

  36.     #define SPI_MISO_DDR  DDRB
  37.     #define SPI_MISO_PORT PORTB
  38.     #define SPI_MISO_BIT  4

  39.     #define SPI_PORT_INI  {\
  40.            SPI_CS_PORT |= 1<<SPI_CS_BIT;\
  41.            SPI_SCK_PORT |= 1<<SPI_SCK_BIT;\
  42.            SPI_MOSI_PORT |= 1<<SPI_MOSI_BIT;\
  43.            SPI_MISO_PORT |= 1<<SPI_MISO_BIT;\
  44.            \
  45.            SPI_CS_DDR &= ~(1<<SPI_CS_BIT);\
  46.            SPI_SCK_DDR &= ~(1<<SPI_SCK_BIT);\
  47.            SPI_MOSI_DDR &= ~(1<<SPI_MOSI_BIT);\
  48.            SPI_MISO_DDR |= 1<<SPI_MISO_BIT;\
  49.          }
  50.     unsigned char spi_buf[850]={0,0,0,0,0,0,0,0,0};//语音信息存储区
  51.     volatile unsigned char spi_ok=0;
  52.     unsigned int  spi_rxd_count=0;
  53.     unsigned int  data_length=0;
  54.     unsigned char is_head=0;
  55.     unsigned char tmp="0";
  56.     //格式:帧头(1字节)数据区长度(2字节)数据区(包括命令字 文本编码格式 待合成文本)
  57.     //测试音“科大讯飞”
  58.     //unsigned char com_buf[13]={0XFD,0X00,0X0A,0X01,0X00,0XBF,0XC6,0XB4,0XF3,0XD1,0XB6,0XB7,0XC9};
  59.     /************************************************************
  60.     *   函数名称:void SPI_Low()
  61.     *   功    能:SPI初始化为低速模式
  62.     *   入口参数:无
  63.     *   出口参数:无
  64.     ************************************************************/
  65.     void SPI_Low(void)
  66.     {
  67.         SPCR &= ~_BV(DORD);
  68.     SPCR =   _BV(SPE)|_BV(MSTR)|_BV(SPR0);
  69.     SPSR &= ~_BV(SPI2X);
  70.     }
  71.     /************************************************************
  72.     *   函数名称:void SPI_High()
  73.     *   功    能:SPI初始化为高速模式
  74.     *   入口参数:无
  75.     *   出口参数:无
  76.     ************************************************************/
  77.     void SPI_High(void)
  78.     {
  79.     //从模式下速率取决于主机
  80.     //SPCR &= ~_BV(MSTR);//从模式,默认为从机,不用重配置
  81.     SPCR = _BV(SPE)|_BV(SPIE);/* 使能 SPI,中断允许 */
  82.     // SPSR |= _BV(SPI2X);
  83.     }
  84.     /************************************************************
  85.     *   函数名称:void SPI_Init()
  86.     *   功    能:SPI初始化
  87.     *   入口参数:无
  88.     *   出口参数:无
  89.     ************************************************************/
  90.     void SPI_Init(void)
  91.     {
  92.     SPI_High();
  93.     SPI_PORT_INI; /* Spi Initialize */
  94.     SPSR = 0x00;
  95.     tmp = SPSR;
  96.     tmp = SPDR; //清空SPI,和中断标志,使SPI空闲

  97.     }
  98.     /************************************************************
  99.     *   函数名称: void port_init(void)
  100.     *   功    能:端口初始化
  101.     *   入口参数:无
  102.     *   出口参数:无
  103.     ************************************************************/
  104.     void port_init(void)
  105.     {
  106.     PORTC=0xfe;//1111 1110 PC0上电输出4040为就绪状态
  107.     DDRC=0xfd;//1111 1101  PC1检测4040状态,配置为输入; PC0输出4040状态
  108.     PORTD = 0x00;//无上拉
  109.     DDRD  = 0x00;//输入
  110.     }
  111.     /************************************************************
  112.     *   函数名称:init_devices()
  113.     *   功    能:系统初始化
  114.     *   入口参数:无
  115.     *   出口参数:无
  116.     ************************************************************/
  117.     void init_devices(void)
  118.     {
  119.     //stop errant interrupts until set up
  120.     cli(); //disable all interrupts
  121.     port_init();
  122.     uart_init();
  123.     SPI_Init();
  124.     MCUCR = 0x00;
  125.     GICR  = 0x00;
  126.     TIMSK = 0x00; //timer interrupt sources
  127.     sei(); //re-enable interrupts
  128.     //all peripherals are now initialized

  129.     }
  130.     /************************************************************
  131.     *   函数名称:SIGNAL(SIG_SPI)
  132.     *   功    能:spi中断
  133.     *   入口参数:无
  134.     *   出口参数:无
  135.     ************************************************************/
  136.     SIGNAL(SIG_SPI)//spi中断
  137.     {
  138.       tmp="SPDR";
  139.       if(is_head==0)
  140.       {
  141.         if(tmp==0xfd) //判断帧头
  142.         is_head=1;
  143.       }
  144.       if(is_head==1)
  145.       {   
  146.          spi_buf[spi_rxd_count]=tmp; //存入spi数据存储区
  147.          spi_rxd_count++;  //spi接收数据计数加1
  148.       }
  149.       if(spi_rxd_count==3) //如果接收到了3个字节,则计算数据长度,共两字节,高字节在前,低字节在后
  150.       {
  151.          data_length=spi_buf[1];
  152.          data_length=(data_length<<8)|spi_buf[2];
  153.       }   
  154.       if(spi_rxd_count==(data_length+3))//判断一帧数据是否结束
  155.       {
  156.          spi_ok=1;
  157.       }

  158.     }
  159.     /************************************************************
  160.     *   函数名称:int  main()
  161.     *   功    能:主函数
  162.     *   入口参数:无
  163.     *   出口参数:无
  164.     ************************************************************/
  165.     int  main()
  166.     {
  167.     init_devices();
  168.     //_delay_ms(1000); _delay_ms(1000); _delay_ms(1000);
  169.     //send_string(com_buf , 13); //测试音“科大讯飞”
  170.     wdt_enable(WDTO_1S); //看门狗初始化为1秒
  171.     wdt_reset();//喂狗
  172.       while(1)
  173.       {  
  174.          if(spi_ok)
  175.          {
  176.            cli();//关中断
  177.            BUSY_4040;//忙
  178.            _delay_ms(10);
  179.         wdt_reset();//喂狗
  180.            send_string(spi_buf ,spi_rxd_count ); //向语音芯片发送信息
  181.         wdt_reset();//喂狗  
  182.            spi_ok=0;
  183.         spi_rxd_count=0;
  184.         data_length=0;
  185.         is_head=0;
  186.            _delay_ms(10);
  187.            sei();//开中断
  188.          }
  189.          if(CHECK_4040==0) //检测语音芯片状态
  190.          {
  191.            READY_4040; //就绪
  192.          }
  193.          else BUSY_4040;//忙
  194.          wdt_reset();//喂狗
  195.       }

  196.     }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

37

主题

306

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部