打印
[Atmel]

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

[复制链接]
1186|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
春风的暖暖|  楼主 | 2015-8-31 21:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
由于第一次用MEGA8的SPI从模式,程序使用中断模式接收,刚开始spi不能进入中断,网上查资料,
  有网友把MOSI方向设为输出能解决问题,按照此方法果然进入了中断,程序顺利完成并打开看门狗。
  试着把MOSI又改为输入,程序运行正常,有待进一步验证。
uart.h
extern void uart_init(void);
extern void send_char(unsigned char c);
extern void send_string(unsigned char * string , unsigned int strLen);

uart.c
    #include<avr/io.h>
    #include <avr/wdt.h>
    #include<util/delay.h>
    #include<avr/eeprom.h>
    #include<avr/pgmspace.h>
    #include<avr/interrupt.h>
    #include "uart.h"
    /************************************************************
    *   函数名称:void uart_init()
    *   功    能:串口初始化
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    void uart_init(void)
    {
    UCSRB = 0x00; //disable while setting baud rate
    UCSRA = 0x00;
    UCSRC = (1<<URSEL) | 0x06;//异步,8位数据,无奇偶校验,一个停止位,无倍速
      /*
        UBRRH与UCSRC共用I/O 地址。因此访问该地址时需注意以下问题。
        写访问
        当在该地址执行写访问时, USART 寄存器选择位(URSEL)控制被写入的寄存器。
        若URSEL为0,对UBRRH值更新;若URSEL为1,对UCSRC设置更新
      
        读访问
        对UBRRH 或UCSRC 寄存器的读访问则较为复杂。但在大多数应用中,基本不需要读这些寄存器
      
      
        没有UBRR这个16位寄存器,因为UBRRL(0x09)/UBRRH(0x20)的地址不连续,而且UBRRH跟UCSRC共用地址
      
      
        U2X=0时的公式计算
        UBRRL= (F_CPU/BAUDRATE/16-1)%256;
        UBRRH= (F_CPU/BAUDRATE/16-1)/256;
        U2X=1时的公式计算
        UBRRL= (F_CPU/BAUDRATE/8-1)%256;
        UBRRH= (F_CPU/BAUDRATE/8-1)/256;
    */
    /*------也可根据数据手册的[波特率设置的例子]查得---------*/
    UBRRL = 0x2F;   //9600
    UBRRH = 0x00; //set baud rate hi
    UCSRB = 0x18; //使能接收,使能发送
    }
    /************************************************************
    *   函数名称:void send_char()
    *   功    能:串口发送单字符
    *   入口参数:unsigned char c
    *   出口参数:无
    ************************************************************/
    void send_char(unsigned char c)
    {
    while( !(UCSRA & (1<<UDRE)) );
    UDR=c;
    }
    /************************************************************
    *   函数名称:void send_string()
    *   功    能:串口发送字符串
    *   入口参数:unsigned char * string , unsigned int strLen
    *   出口参数:无
    ************************************************************/
    void send_string(unsigned char * string , unsigned int strLen)
    {
      unsigned int i="0";
      do
       {
    send_char( *(string +i) );
    i++;
       }while( i < strLen );
    }



相关帖子

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

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

    #define SPI_SCK_DDR  DDRB
    #define SPI_SCK_PORT PORTB
    #define SPI_SCK_BIT  5

    #define SPI_MOSI_DDR  DDRB
    #define SPI_MOSI_PORT PORTB
    #define SPI_MOSI_BIT  3

    #define SPI_MISO_DDR  DDRB
    #define SPI_MISO_PORT PORTB
    #define SPI_MISO_BIT  4

    #define SPI_PORT_INI  {\
           SPI_CS_PORT |= 1<<SPI_CS_BIT;\
           SPI_SCK_PORT |= 1<<SPI_SCK_BIT;\
           SPI_MOSI_PORT |= 1<<SPI_MOSI_BIT;\
           SPI_MISO_PORT |= 1<<SPI_MISO_BIT;\
           \
           SPI_CS_DDR &= ~(1<<SPI_CS_BIT);\
           SPI_SCK_DDR &= ~(1<<SPI_SCK_BIT);\
           SPI_MOSI_DDR &= ~(1<<SPI_MOSI_BIT);\
           SPI_MISO_DDR |= 1<<SPI_MISO_BIT;\
         }
    unsigned char spi_buf[850]={0,0,0,0,0,0,0,0,0};//语音信息存储区
    volatile unsigned char spi_ok=0;
    unsigned int  spi_rxd_count=0;
    unsigned int  data_length=0;
    unsigned char is_head=0;
    unsigned char tmp="0";
    //格式:帧头(1字节)数据区长度(2字节)数据区(包括命令字 文本编码格式 待合成文本)
    //测试音“科大讯飞”
    //unsigned char com_buf[13]={0XFD,0X00,0X0A,0X01,0X00,0XBF,0XC6,0XB4,0XF3,0XD1,0XB6,0XB7,0XC9};
    /************************************************************
    *   函数名称:void SPI_Low()
    *   功    能:SPI初始化为低速模式
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    void SPI_Low(void)
    {
        SPCR &= ~_BV(DORD);
    SPCR =   _BV(SPE)|_BV(MSTR)|_BV(SPR0);
    SPSR &= ~_BV(SPI2X);
    }
    /************************************************************
    *   函数名称:void SPI_High()
    *   功    能:SPI初始化为高速模式
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    void SPI_High(void)
    {
    //从模式下速率取决于主机
    //SPCR &= ~_BV(MSTR);//从模式,默认为从机,不用重配置
    SPCR = _BV(SPE)|_BV(SPIE);/* 使能 SPI,中断允许 */
    // SPSR |= _BV(SPI2X);
    }
    /************************************************************
    *   函数名称:void SPI_Init()
    *   功    能:SPI初始化
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    void SPI_Init(void)
    {
    SPI_High();
    SPI_PORT_INI; /* Spi Initialize */
    SPSR = 0x00;
    tmp = SPSR;
    tmp = SPDR; //清空SPI,和中断标志,使SPI空闲

    }
    /************************************************************
    *   函数名称: void port_init(void)
    *   功    能:端口初始化
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    void port_init(void)
    {
    PORTC=0xfe;//1111 1110 PC0上电输出4040为就绪状态
    DDRC=0xfd;//1111 1101  PC1检测4040状态,配置为输入; PC0输出4040状态
    PORTD = 0x00;//无上拉
    DDRD  = 0x00;//输入
    }
    /************************************************************
    *   函数名称:init_devices()
    *   功    能:系统初始化
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    void init_devices(void)
    {
    //stop errant interrupts until set up
    cli(); //disable all interrupts
    port_init();
    uart_init();
    SPI_Init();
    MCUCR = 0x00;
    GICR  = 0x00;
    TIMSK = 0x00; //timer interrupt sources
    sei(); //re-enable interrupts
    //all peripherals are now initialized

    }
    /************************************************************
    *   函数名称:SIGNAL(SIG_SPI)
    *   功    能:spi中断
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    SIGNAL(SIG_SPI)//spi中断
    {
      tmp="SPDR";
      if(is_head==0)
      {
        if(tmp==0xfd) //判断帧头
        is_head=1;
      }
      if(is_head==1)
      {   
         spi_buf[spi_rxd_count]=tmp; //存入spi数据存储区
         spi_rxd_count++;  //spi接收数据计数加1
      }
      if(spi_rxd_count==3) //如果接收到了3个字节,则计算数据长度,共两字节,高字节在前,低字节在后
      {
         data_length=spi_buf[1];
         data_length=(data_length<<8)|spi_buf[2];
      }   
      if(spi_rxd_count==(data_length+3))//判断一帧数据是否结束
      {
         spi_ok=1;
      }

    }
    /************************************************************
    *   函数名称:int  main()
    *   功    能:主函数
    *   入口参数:无
    *   出口参数:无
    ************************************************************/
    int  main()
    {
    init_devices();
    //_delay_ms(1000); _delay_ms(1000); _delay_ms(1000);
    //send_string(com_buf , 13); //测试音“科大讯飞”
    wdt_enable(WDTO_1S); //看门狗初始化为1秒
    wdt_reset();//喂狗
      while(1)
      {  
         if(spi_ok)
         {
           cli();//关中断
           BUSY_4040;//忙
           _delay_ms(10);
        wdt_reset();//喂狗
           send_string(spi_buf ,spi_rxd_count ); //向语音芯片发送信息
        wdt_reset();//喂狗  
           spi_ok=0;
        spi_rxd_count=0;
        data_length=0;
        is_head=0;
           _delay_ms(10);
           sei();//开中断
         }
         if(CHECK_4040==0) //检测语音芯片状态
         {
           READY_4040; //就绪
         }
         else BUSY_4040;//忙
         wdt_reset();//喂狗
      }

    }

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

37

主题

306

帖子

2

粉丝