专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

AVR atmega16协议的制定

作者:未知   来源:网上一位高手   点击数:  更新时间:2014年06月01日   【字体:

 此规定的协议时通过上位机发送指令,使单片机在不同的时间内发送读取的温度值

 
#define F_CPU 8000000UL
#include
#include
#include
#define BAUD 9600  //定义波特率
#define uchar unsigned char
#define uint unsigned int
#define FRAMING_ERROR  _BV(FE)  //接收帧出错
#define PARITY_ERROR   _BV(PE)  //校验出错
#define DATA_OVERRUN  _BV(DOR)  //数据溢出
#define DATA_REGISTER_EMPTY _BV(UDRE) //数据寄存器为空,当写入UDR(TXB)的字符被传送到移位寄存器中时,该位置1, 表示UDR可以写入新的数据。
#define RX_COMPLETE  _BV(RXC)  //接收器接收一个完整的数据帧后,接收到的数据驻留在接收缓冲器中,此时RXC标志。会置1(产生接收完成中断),
        //表示接收器收到一个数据在接收缓冲器中,未被读取。当RXC为“0”时,表示数据接收器为空。
#define TX_BUFFER_SIZE 6  //发送缓冲器大小      
//USART接收缓冲区
#define RX_BUFFER_SIZE 5   //接收缓冲器大小
   
uchar rx_buffer[RX_BUFFER_SIZE]={0,0,1,0,0};  //定义接收缓冲区
 
//定义接收缓冲区环形队列的控制指针,rx_wr_index为写指针,rx_rd_index为读指针,rx_counter为存放在队列中的已接受到字符数
#if RX_BUFFER_SIZE <256
uchar rx_wr_index,rx_rd_index,rx_counter;
#else
uint rx_wr_index,rx_rd_index,rx_counter;
#endif
//端口状态初始化设置函数
//void Port_Init()
//{
 //PORTD = 0X00;          //USART 的发送接收端口分别为 PD0 和 PD1
 //DDRD |= (1 << PD1);   //PD0 为接收端口,置为输入口;PD1 为发送端口,置为输出口
//}
void Usart_Init()
{
 UCSRA = 0X00;
 UCSRC |= (1<<URSEL) | (1 << UCSZ1) | (1 << UCSZ0);  //异步,数据格式 8,N,1
 //UCSRC 寄存器与 UBRRH 寄存器共用相同的 I/O 地址,写 UCSRC 时, URSEL 应设置为 1。
 UBRRL = (F_CPU / BAUD / 16 - 1) % 256;            //波特率设置
 UBRRH = (F_CPU / BAUD / 16 - 1) / 256;
 UCSRB |= (1 << TXEN)|(1<<RXEN)|(1<<RXCIE)|(1<<TXCIE);       //接收发送接收使能,并使能发送接收标志中断,
}
 
uchar rx_buffer_overflow; //接收缓冲区溢出标志
uchar recvFlag;
//接收中断服务
ISR(USART_RXC_vect)
{
 uchar status,data;
 status=UCSRA;  //读取接收状态标志位,必须先读,当读了UDR以后,UCSRA便自动清零了
 data=UDR;     //读取USART数据寄存器
 if(!recvFlag)
 {
  if ((status &(FRAMING_ERROR|PARITY_ERROR|DATA_OVERRUN)) ==0)
 {
  rx_buffer[rx_counter]=data;  //将字符填充到接收缓冲区队列中
  rx_counter++;
  //Putchar(recvFlag);
  //Putchar(data);
  //
  //if((rx_counter++)==5)
  //{
   //rx_counter=0;
   //recvFlag=1;
  //}
  
  //Putchar(rx_counter);
  //制订协议:第一位起始位:BBH;第二位命令字:0AH代表控制数据传送的时间,0BH代表控制温度上下限值,
  //第三位参数字,第四位校验码:命令字与参数字的异或,最后一位结束位:EEH
  switch(rx_counter)
  {
   case 1:        //检验起始位
    if(data!=0XBB) rx_counter=0;break;
   case 4:        //校验校验字
    if(data != rx_buffer[1]^rx_buffer[2])
    
    //Putchar("FF");
    rx_counter=0; 
    
    
    //Putchar(rx_buffer[0]);
    //Putchar(rx_buffer[1]);
    //Putchar(rx_buffer[2]);
    //Putchar(rx_buffer[3]);
    //Putchar(rx_buffer[4]);  
    break;
   case 5: //校验结束字
       
    rx_counter=0;
    if(data ==0xEE) recvFlag=1;break; //recvFlag=1表示正确接收一个数据包 
  }
 }
 } 
 
}
 
 
//从接收队列中读取一个数据
 
uchar Getchar(void)
{
 uchar data;
 while(rx_counter==0);  //接收缓冲区中没有数据可以读取,等待。
 data=rx_buffer[rx_rd_index];  //读取缓冲队列中的数据
 if(++rx_rd_index==RX_BUFFER_SIZE)
 rx_rd_index=0;
 cli();     //禁止中断,这一步非常重要
 --rx_counter;  //队列未读数据个数减1.因为该变量会在接收中断中改变,为了防止冲突,所以改动前应临时禁止中断。程序相当可靠
 sei();  //使能中断
 return data;
}
 
//发送缓冲区
uchar tx_buffer[TX_BUFFER_SIZE];  //定义发送缓冲区
//定义发送缓冲区环形队列的控制指针,tx_wr_index为写指针,tx_rd_index为读指针,tx_counter为存放在队列中的已接受到字符数
uchar tx_wr_index,tx_rd_index,tx_counter;
 
//向USART发送缓冲区写一个字符
void Putchar(unsigned char c)
{
 
 while(tx_counter==TX_BUFFER_SIZE);  //如果发送队列满,等待
 cli();                              //禁止中断
 if (tx_counter||((UCSRA & DATA_REGISTER_EMPTY)==0))
 {
  tx_buffer[tx_wr_index]=c;
  if(++tx_wr_index==TX_BUFFER_SIZE)
     tx_wr_index=0;
  ++tx_counter;
 }
 else
    UDR=c;
    sei();
}
 
ISR(USART_TXC_vect)
{
 if(tx_counter)     //发送队列中还未发送的数据
 {
  --tx_counter;  //未发送数据减1。
  
  UDR = tx_buffer[tx_rd_index]; //发送一个数据。
   
  if(++tx_rd_index==TX_BUFFER_SIZE)
  
   tx_rd_index=0;    //读指针指向下一个未发送的数据,如果指到了队列尾部,则回到队列头部。
 } 
}
关闭窗口

相关文章