comm.c
来自「这是一个AVR单片机的串行通讯模块 大家可以合理的用到自己的实验中」· C语言 代码 · 共 429 行 · 第 1/2 页
C
429 行
* 2> COMM_TXD_OK 发送数据进入缓存OK
* 说 明 : 无
********************************************************************************************************/
#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
/********************************************************************************************************
* 功 能 : COMM1 发送1 BYTE数据
* 入 口 : 'Date' 发送的数据
* 返 回 : 1> COMM_TXD_OK 发送数据OK
* 2> COMM_TXD_FALSE 发送失败 一般是发送缓存已满
* 说 明 : 1> UDR发送寄存器为空时直接把要发送的数据放到发送缓存
* 2> UDR发送寄存器为忙时来不及发的数据进入到发送缓存
* 3> 发送缓存满时直接返回发送失败
********************************************************************************************************/
/*
INT8U Comm1TxPutChar (INT8U Data)
{
COMM_ENTER_CRITICAL(); // 进入临界
if (!bComm1CanSend) { // 判断串口直接发送允许标志位 0为允许
bComm1CanSend = 1; // 设置为忙
UDR = Data; // 发送出数据
COMM_EXIT_CRITICAL(); // 退出临界
return (COMM_TXD_OK); // 返回代码为发送OK
}
if (Comm1TxBufCtr >= COMM1_TXD_SIZE) { // 判断发送缓存计数器是否为最大发送缓存
COMM_EXIT_CRITICAL(); // 是退出临界 不处理
return (COMM_TXD_FALSE); // 发送缓存满 返回代码为发送失败
} else {
Comm1TxInBuf(Data); // 来不及发送的数据一直等到进入发送缓存
COMM_EXIT_CRITICAL(); // 退出临界
return (COMM_TXD_OK); // 返回代码为发送OK
}
}
*/
/********************************************************************************************************
* 功 能 : COMM1 发送N BYTE数据
* 入 口 : 'p' 指向发送消息的指针
* 'len' 发送数据的长度
* 返 回 : 返回实际发送的数据长度
* 说 明 : 1> 如果是发送失败 则直接返回 这样在多任务里面就可以延时N个周期再尝试重发数据 这样就不会在这里
* 多等更多的时间 但这种情况不是绝对的 根据波特率是有很大的关系
* 2> 建议发送时的缓存最好保证>=即将发送的数据长度 数据流之间能留一定的时间间隔保证发送数据
* 3> 发送的数据长度大于实际能缓存的长度时 波特率是影响其工作效率的主要因素 MCU中的RAM一般比较小
********************************************************************************************************/
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); // 返回实际发送的数据长度
}
/********************************************************************************************************
* 功 能 : 串口1读1则数据
* 入 口 : 'err' 返回错误信息的指针
* 返 回 : 1> 读到的数据
* 2> err=COMM_RXD_EMPTY 接收缓存没有数据
* 3> err=COMM_RXD_OK 正确在接收缓存读到数据
* 说 明 : 1> 在调用此函数前 最好用Comm1RxGetNMsgs函数检查一下接收缓存里面有没有信息
* 2> 如果不按1>的用法用 则要对返回的错误代码分析
********************************************************************************************************/
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); // 返回接收缓存计数
}
/********************************************************************************************************
* 功 能 : 一次串口1读N则数据
* 入 口 : 'p' 返回数据信息的指针
* 'len' 读的数据长度 < COMM1_RXD_SIZE
* 返 回 : 1> COMM_RXD_EMPTY 读数据为空 一般是len为空 或接收缓存中没有数据
* 2> COMM_RXD_FALSE 错误读数据 一般为len大于数据接收缓存中的数据
* 3> COMM_RXD_OK 数据正确读到
* 说 明 : 1> 对于返回参数2> 可以使用Comm1RxGetNMsgs 先取得缓存中的数据个数再一次读走
********************************************************************************************************/
#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
/********************************************************************************************************
* 功 能 : 初始化串口1的各种变量
* 入 口 : 无
* 返 回 : 无
* 说 明 : 无
********************************************************************************************************/
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
/********************************************************************************************************
* End Of File
********************************************************************************************************/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?