打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
AVR完整通讯代码
发现这个不错的avr的串口通讯代码,尽管自己不会采用给代码(因为我的目标很简单,没有必要这么复杂),还是收藏于此,以备后用。
在此谢谢原创者。

[code]

#ifdef COMM_GLOBALS
#define COMM_EXT
#else
#define COMM_EXT extern
#endif


#define COMM_MODULE_EN         1           // 串口模块总使能  0禁止


                                             // 当串口的接收需要任务协助处理时下面两个定义有效
//#define TaskComm1Prio          1          // 定义串口0接收任务ID 注意: 在CONFIG.H中统一定义
//#define TaskComm2Prio          2          // 定义串口1接收任务ID
#define COMM1_MEM_SEL                        // 串口0各种控制变量存储区选择   非C51一般为空
#define COMM2_MEM_SEL                        // 串口1各种控制变量存储区选择   非C51一般为空
#define COMM_CONST_SEL                       // 串口数据常量存储区选择       非C51一般为const或static
#define COMM0_VECTOR                         // 串口0中断函数入口编号
#define COMM1_VECTOR                         // 串口1中断函数入口编号
#define X0N                    17           // 流控制字符 继续发送 20%
#define XOFF                   19           // 流控制字符 停止发送 70%

////////////////////////////////////////////////------------串口配置----------
#define COMM_MODE              1            // 通信模式    0异步正常模式 1异步倍速模式 2同步主机模式                                             
#define COMM_MORE_CPU_MODE     0            // 多处理器模式 1为多处理器模式有效 0为无效
#define COMM_ACCEPT_ISR_EN     1            // 接收结束中断         (1)使能  (0)禁止
#define COMM_SEND_ISR_EN       1            // 发送结束中断         (1)使能  (0)禁止
#define COMM_DATAFREE_ISR_EN   1            // 数据寄存器空中断     (1)使能  (0)禁止
#define COMM_SYN_CLOCK         1            // 同步工作模式时钟极性 (1)下降沿 (0)上升沿

                                             // 两个处理CLK模块临界数据的两个宏 这里使用OS的临界宏 
#define COMM_ENTER_CRITICAL()  OS_ENTER_CRITICAL() // 进入临界宏 默认COMM_ENTER_CRITICAL() EA=0   
#define COMM_EXIT_CRITICAL()   OS_EXIT_CRITICAL() //退出临界宏 默认COMM_ENTER_CRITICAL() EA=1
    
                                             // 串口0的常量定义
#define COMM1_UNIT_EN          1            // 串口0模块使能                                 0禁止
 #define COMM1_DATA_STREAM_EN 0            // ASCII方式通讯时可采样XON/XOFF数据流模式来保证数据传输
 #define COMM1_OS_SEL         1            // 选择在RTOS中使用则调用OSIntSendSignal 通知接收任务处理
                                             // 串口数据则启用定义TaskComm1Prio即接收任务ID  0=禁止
 #define COMM1_OS_SIGNAL_SEL  1            // 0选择发送信号 1选择释放信号量 同时COMM1_OS_SEL要使能 
                                             //  来通知接收任务处理数据                           
 #define COMM1_RXD_EN         1            // 串口0接收部分使能                             0禁止
 #define COMM1_GETNMSGS_EN    0            // 串口0的数据计数检测函数使能                   0禁止
 #define COMM1_GETS_EN        0            // 串口0接收多数据                               0禁止
 #define COMM1_RXD_SIZE       255          // 串口0的接收缓存配置 需要立即读数据 否则弃数据 必须>=1
 #define COMM1_TXD_EN         1            // 串口0发送部分使能                             0禁止
 #define COMM1_PUTS_EN        0            // 串口0发送多数据                               0禁止
 #define COMM1_TXD_SIZE       128          // 串口0的发送缓存配置                           必须>=1
                                                                               

//////////////////////////////////////////////// --------------串口的各种返回信息 不能更改------------
#define COMM_ERR               0            // 串口配置有错误 
#define COMM_NO_ERR            1            // 串口配置没有错误
#define COMM_BAD_BAUD          2            // 波特率错误
#define COMM_BAD_MODE          3            // 串口工作为错误的工作方式
#define COMM_RXD_EMPTY         4            // 接收缓存没有数据 为空
#define COMM_RXD_FALSE         5            // 接收数据失败 只多字节接收时返回此信息
#define COMM_RXD_OK            6            // 接收数据正确
#define COMM_TXD_FALSE         7            // 发送失败
#define COMM_TXD_OK            8            // 发送正确
#define COMM_TXD_FLOOD         9            // 发送数据溢出 快速或多字节数据发送时 缓存溢出
          

////////////////////////////////////////////

#if  (COMM_MODE == 0)||(COMM_MODE == 1)        // 异步正常模式串,异步倍速模式串
   #define UMSEL_MODE         0
   #define UCPOL_MODE         0
 #elif COMM_MODE == 2                          // 同步模式串
   #define UMSEL_MODE         BIT(UMSEL)
   #if COMM_SYN_CLOCK == 0                      // 同步工作模式时钟极性
       #define UCPOL_MODE     0
     #else
       #define UCPOL_MODE     BIT(UCPOL)
   #endif
 #else                                         // 选择其他模式 则停止编译
   #error "(COMM_MODE)通信模式设置错误! "
#endif

#if    COMM_MORE_CPU_MODE == 0               // 处理器模式 1为多处理器模式有效 0为无效
   #define MPCM_MODE              0           //
 #elif  COMM_MORE_CPU_MODE == 1
   #define MPCM_MODE              BIT(MPCM)
 #else
   #error "请正确配置多处理器模式中断使能信号 (COMM_MORE_CPU_MODE)!"
#endif

#if    COMM_ACCEPT_ISR_EN == 0               // 接收结束中断 (1)使能 (0)禁止
   #define RXCIE_MODE             0           //
 #elif  COMM_ACCEPT_ISR_EN == 1
   #define RXCIE_MODE             BIT(RXCIE)
 #else
   #error "请正确配置接收结束中断中断使能信号 (COMM_ACCEPT_ISR_EN)!"
#endif

#if    COMM_SEND_ISR_EN == 0                 // 发送结束中断 (1)使能 (0)禁止
   #define TXCIE_MODE              0          //
 #elif  COMM_SEND_ISR_EN == 1
   #define TXCIE_MODE              BIT(TXCIE)
 #else
   #error "请正确配置发送结束中断中断使能信号 (COMM_SEND_ISR_EN)!"
#endif

#if    COMM_DATAFREE_ISR_EN == 0               // 数据寄存器空中断 (1)使能 (0)禁止
   #define UDRIE_MODE             0           //
 #elif  COMM_DATAFREE_ISR_EN == 1
   #define UDRIE_MODE             BIT(UDRIE)
 #else
   #error "请正确配置数据寄存器空中断使能信号 (COMM_DATAFREE_ISR_EN)!"
#endif
////////////////////////////////////////////////
#define none 0
#define even 2
#define odd 3

#if COMM_MODULE_EN > 0


#endif


                                             
INT8U   Comm1CfgPort    (INT32U baud, INT8U parity, INT8U bits, INT8U stops);
void    Comm1VarInit    (void);            
                                             
INT8U   Comm1RxGetChar  (INT8U *Data);
INT8U   Comm1RxGetNMsgs (void);
INT8U   Comm1RxGetsChar (INT8U *s, INT8U len);

                                             
INT8U   Comm1TxInBuf (INT8U Data);          // 数据进入发送缓存    
#define Comm1TxPutChar Comm1TxInBuf
//INT8U   Comm1TxPutChar  (INT8U Data);
INT8U   Comm1TxPutsChar (INT8U *s, INT8U len);

[/code]

[code]

#define COMM_GLOBALS
#include "includes.h"

 
#if     COMM_MODULE_EN > 0
    

#ifndef MCU_Fosc                             // MCU的晶振频率设置 这是计算波特率必须的参数 
#error "no defien MCU_Fosc      e.g. #define MCU_Fosc 11059200L"
#endif

static INT8U COMM1_MEM_SEL Comm1RxBuf[COMM1_RXD_SIZE]; // 串口1接收分配缓存
static INT8U COMM1_MEM_SEL Comm1RxBufCtr;              // 串口1接收数据个数计数器
static INT8U COMM1_MEM_SEL Comm1RxInIx;                // 串口1接收数据入缓存位置索引
static INT8U COMM1_MEM_SEL Comm1RxOutIx;               // 串口1接收数据出缓存位置索引

static BOOL               bComm1CanSend;              // 串口1发送忙标志 0=不忙 1=忙
static INT8U COMM1_MEM_SEL Comm1TxBuf[COMM1_TXD_SIZE]; // 串口1发送分配缓存
static INT8U COMM1_MEM_SEL Comm1TxBufCtr;              // 串口1发送数据个数计数器
static INT8U COMM1_MEM_SEL Comm1TxInIx;                // 串口1发送数据入缓存位置索引
static INT8U COMM1_MEM_SEL Comm1TxOutIx;               // 串口1发送数据出缓存位置索引

#define CR PutString("\r\n")                 //发送一个回车换行
#define NUL putstring("{post.content}")                  //发送一个空格


#if   (COMM1_UNIT_EN > 0 && COMM1_RXD_EN > 0) || ( COMM1_UNIT_EN > 0 && COMM1_TXD_EN > 0)
INT8U Comm1CfgPort (INT32U baud, INT8U parity, INT8U bits, INT8U stops)
{
   INT8U UCSRC_TEMP;                           //UBRRH和UCSRC的读写操作很特殊
   
   
   COMM_ENTER_CRITICAL();
#if  COMM_MODE == 0
   UBRRH = (INT8U)((MCU_Fosc/16/(baud+1))>>8); // 设异步正常模式串口波特率
   UBRRL = (INT8U)((MCU_Fosc/16/(baud+1)));
   UCSRA = MPCM_MODE;                          // 多机模式设定
#elif COMM_MODE == 1
   UBRRH = (INT8U)((MCU_Fosc/8/(baud+1))>>8);  // 设异步倍速模式串口波特率
   UBRRL = (INT8U)((MCU_Fosc/8/(baud+1)));
   UCSRA = BIT(U2X)|MPCM_MODE;                 // 倍速发送和多机模式设定
#elif COMM_MODE == 2
   UBRRH = (INT8U)((MCU_Fosc/2/(baud+1))>>8);  // 设同步模式串口波特率
   UBRRL = (INT8U)((MCU_Fosc/2/(baud+1)));
   UCSRA = MPCM_MODE;                          //
#endif
         // 接收中断,发送中断,数据寄存器空中断,同步时钟极性,发送使能,接收使能设定
   UCSRB =RXCIE_MODE|TXCIE_MODE|UDRIE_MODE|UCPOL_MODE|BIT(RXEN)|BIT(TXEN);
   
   switch (bits) {
       case 5 :
           UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE;
           break;
       case 6:
           UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ0);
           break;
       case 7:
           UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1);
           break;
       case 8 :
           UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1)|BIT(UCSZ0);
           break;
       case 9 :
           SETBIT(UCSRB,BIT(UCSZ2));
           UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1)|BIT(UCSZ0);
           break;
       default:
           UCSRC_TEMP = BIT(URSEL)|UMSEL_MODE|BIT(UCSZ1)|BIT(UCSZ0); //默认为8BIT
           break;
   }
   
   if (stops == 2){                                                 // 设停止位
       SETBIT(UCSRC_TEMP,(BIT(URSEL)+BIT(USBS)));
   }

   switch (parity) {
       case none :                                                 // 无校验
           break;
       case 1:                                                     // 系统保留
           break;
       case even:
           SETBIT(UCSRC_TEMP,(BIT(URSEL)+BIT(UPM1)));              // 偶校验
           break;
       case odd :
           SETBIT(UCSRC_TEMP,(BIT(URSEL)+BIT(UPM1)+BIT(UPM0)));    // 奇校验
           break;
       default:                                                    //默认为无校验
           break;
   }
   UCSRC = UCSRC_TEMP;
   
   COMM_EXIT_CRITICAL();
   return (COMM_NO_ERR);
}
#endif

ISR(SIG_UART_RECV){
   //COMM_ENTER_CRITICAL();                 // 进入临界处理
   
   if (Comm1RxBufCtr < COMM1_RXD_SIZE) {
       Comm1RxBufCtr++;                     // 接收缓存计数器加1
       Comm1RxBuf[Comm1RxInIx++] = UDR;     // 接收到的数据进缓存
       if (Comm1RxInIx >= COMM1_RXD_SIZE) {
           Comm1RxInIx = 0;
       }
   }       
   //COMM_EXIT_CRITICAL();                  // 退出临界
}

ISR(SIG_UART_TRANS){
   //COMM_ENTER_CRITICAL();                 // 进入临界
#if COMM_DATAFREE_ISR_EN == 0
   if (Comm1TxBufCtr > 0) {                 // 检查发送消息缓存区是否为空 不为空则继续发数据
       Comm1TxBufCtr--;                     // 缓存计数器减1
       UDR = Comm1TxBuf[Comm1TxOutIx++];    // 读走一个数据到发送寄存器,自动清发送中断标志
       if (Comm1TxOutIx >= COMM1_TXD_SIZE) {
           Comm1TxOutIx = 0;
       }
   } else {
       bComm1CanSend    = 0;               // 发送标志为0表示 可以直接发送信息
   }
#endif
   //COMM_EXIT_CRITICAL();                  // 退出临界
}


#if COMM_DATAFREE_ISR_EN > 0
ISR(SIG_UART_DATA){
   //COMM_ENTER_CRITICAL();                 // 进入临界
   if (Comm1TxBufCtr > 0) {                 // 检查发送消息缓存区是否为空 不为空则继续发数据
       Comm1TxBufCtr--;                     // 缓存计数器减1
       UDR = Comm1TxBuf[Comm1TxOutIx++];    // 读走一个数据到发送寄存器,自动清发送中断标志
       if (Comm1TxOutIx >= COMM1_TXD_SIZE) {
           Comm1TxOutIx = 0;
       }
   } else {
       CLRBIT(UCSRB,BIT(UDRIE));            // 数据发送完,清数据寄存器中断使能位
       bComm1CanSend    = 0;               // 发送标志为0表示 可以直接发送信息
   }
   //COMM_EXIT_CRITICAL();                  // 退出临界
}
#endif


#if   COMM1_UNIT_EN > 0 && COMM1_TXD_EN > 0
INT8U Comm1TxInBuf (INT8U Data)
{
   INT8U err;
   
   err = COMM_TXD_FLOOD;                    // 设置发送缓存为满
   
   COMM_ENTER_CRITICAL();                   // 进入临界
   if (!bComm1CanSend) {                    // 判断串口直接发送允许标志位 0为允许
       bComm1CanSend = 1;                   // 设置为忙
       UDR          = Data;                // 发送出数据
#if COMM_DATAFREE_ISR_EN > 0
       SETBIT(UCSRB,BIT(UDRIE));            // 数据发送开始,置数据寄存器中断使能位
#endif
       COMM_EXIT_CRITICAL();                // 退出临界
       return (COMM_TXD_OK);                // 返回代码为发送OK
   }
   
   if (Comm1TxBufCtr < COMM1_TXD_SIZE) {    // 处理发送缓存计数器
       err = COMM_TXD_OK;                   // 设置发送缓存为正常
       Comm1TxBufCtr++;                     // 发送缓存计数器加1
       Comm1TxBuf[Comm1TxInIx++] = Data;    // 来不及发送的数据进发送缓存
       if (Comm1TxInIx >= COMM1_TXD_SIZE) { // 处理发送进缓存计数器
           Comm1TxInIx = 0;                // 复位发送进缓存计数器
       }
   }   
   COMM_EXIT_CRITICAL();                    // 退出临界 开始准备发送多字符
   return (err);
}
#endif

INT8U Comm1TxPutsChar (INT8U *s, INT8U len)
{  
   INT8U i;
   
   //COMM_ENTER_CRITICAL();                 // 进入临界
   i = COMM1_TXD_SIZE - Comm1TxBufCtr;      // 实际还有多少可用缓冲区
   //COMM_EXIT_CRITICAL();                  // 退出临界
   if (i > len){                            // 发送数据长度小于可用缓冲区时,
       i = len;                             // 所有数据能全部发送成功
   }else{
       len = i;
   }
   
   while (i--) {                            // 发送数据处理
       Comm1TxInBuf(*s);                    // 发送的数据进入发送缓存
       s++;                                 // 数据指针加1
   }
   
   return (len);                            // 返回实际发送的数据长度
}

INT8U Comm1RxGetChar (INT8U *Data)
{
   INT8U err = COMM_RXD_EMPTY;              // 返回代码为接收为空
 
   COMM_ENTER_CRITICAL();                   // 进入临界
   if (Comm1RxBufCtr > 0) {                 // 检测接收缓存是否有数据
       Comm1RxBufCtr--;                     // 有数据计数器减1
       *Data = Comm1RxBuf[Comm1RxOutIx++];   // 取出数据
       err  = COMM_RXD_OK;                  // 返回代码为读数据正确
       if (Comm1RxOutIx >= COMM1_RXD_SIZE) { // 检查出数据计数器是否大于最大接收缓存
           Comm1RxOutIx = 0;               // 是复位出数据计数器
       }
   }
   COMM_EXIT_CRITICAL();                    // 退出临界
   return (err);
}

INT8U  Comm1RxGetNMsgs (void)
{
   INT8U counter;
   COMM_ENTER_CRITICAL();                   // 进入临界
   counter = Comm1RxBufCtr;                 // 取接收计数器数据
   COMM_EXIT_CRITICAL();                    // 退出临界
   return (counter);                        // 返回接收缓存计数
}


#if   COMM1_UNIT_EN > 0 && COMM1_RXD_EN > 0 && COMM1_GETS_EN > 0
INT8U Comm1RxGetsChar (INT8U *s, INT8U len)
{   
   COMM_ENTER_CRITICAL();                   // 进入临界 处理Comm1RxBufCtr
   if ((len == 0) || (Comm1RxBufCtr == 0)) { // 检查数据长度 和接收缓存是否为空
       COMM_EXIT_CRITICAL();                // 退出临界
       return (COMM_RXD_EMPTY);             // 返回代码为接收空
   }

   if (len > Comm1RxBufCtr) {               // 检查读数长度跟实际接收缓存数据个数
       COMM_EXIT_CRITICAL();                // 退出临界
       return (COMM_RXD_FALSE);             // 返回代码为 读数据失败
   }   
   COMM_EXIT_CRITICAL();                    // 退出临界

                                             // 必须退出临界以便其他的中断响应 否则len大时就会影响中断
   while (len--) {                          // 读走len个数据
       COMM_ENTER_CRITICAL();               // 进入临界 处理Comm1RxBufCtr
       *s++ = Comm1RxBuf[Comm1RxOutIx++];   // 取出数据
       Comm1RxBufCtr--;                     // 接收缓存计数器减1
       if (Comm1RxOutIx >= COMM1_RXD_SIZE) { // 处理接收出数据计数器
           Comm1RxOutIx = 0;                // 复位出数据计数器
       }
       COMM_EXIT_CRITICAL();                // 退出临界
   }
   return (COMM_RXD_OK);                    // 返回代码为 接收到正确数据
}
#endif

void  Comm1VarInit (void)
{
#if COMM1_RXD_EN > 0                         // 初始化接收的各种变量
   Comm1RxBufCtr = 0;
   Comm1RxInIx  = 0;
   Comm1RxOutIx = 0;
#endif

#if COMM1_TXD_EN > 0                         // 初始化发送的各种变量
   Comm1TxBufCtr = 0;
   Comm1TxInIx  = 0;
   Comm1TxOutIx = 0;
   bComm1CanSend = 0;                       // 串口0寄存器发送忙标志
#endif
}


#endif

[/code]

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
检查C 内存泄露的方法 - 指针与内存相关
快速入门丨篇四:如何进行运动控制器与触摸屏通讯?
用arduino单片机,实现与flash虚拟人物ML(关键部位已打码)
头文件互相包含
自动循迹小车——软件设计
公用子函数
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服