📄 usart.c
字号:
#include "msp430x42x.h"
#include "Global.h"
#include "USART.h"
#include "Measure.h" // 测量值
// 串口检查定时器周期(最小4个字节长度时间)
#define TIMER_INTERVAL (15729) // 15ms @ MCLK = 1.048576MHz
#define ERROR_AUTO_RESET (30) // 失控时间, 错误自动修复, 30*15ms = 450ms
// 队列操作错误代码
#define ERR_OK (0)
#define ERR_TX_QUEUE_OVERFLOW (128)
#define ERR_TX_QUEUE_EMPTY (128 + 1)
#define ERR_RX_QUEUE_OVERFLOW (128 + 2)
#define ERR_RX_QUEUE_EMPTY (128 + 3)
// 队列设置
#define FIFO_RX_LENGTH (64) // 最多一次操作30个寄存器
#define FIFO_TX_LENGTH (64)
extern unsigned char Reg_MasterAddress;
unsigned char Queue_Rx[FIFO_RX_LENGTH]; // 接受循环队列
unsigned char Queue_Tx[FIFO_TX_LENGTH]; // 发送循环队列
unsigned int Queue_Rx_SavePostation; // 队列指针: 指向下一个可存放接受数据的位置
unsigned int Queue_Rx_ReadPostation; // 队列指针: 指向下一个将要读取的数据
unsigned int Queue_Tx_SavePostation; // 队列指针: 指向下一个即将发送的位置
unsigned int Queue_Tx_ReadPostation; // 队列指针: 指向下一个可存放发送数据的位置
// CRC
unsigned int Reg_SendCRC = 0xffff; // 对发送数据的CRC计算的全局变量
unsigned int Reg_ReceiveCRC = 0xffff; // 对接收数据的CRC计算的全局变量
// 串口标志和计数
_EXTERN unsigned int Cnt_SendBytes; // 发送数据计数
_EXTERN unsigned int Cnt_ReceiveBytes; // 接受数据技术
_EXTERN unsigned char Flg_ReceiveData; // 接受到有效数据
unsigned int Cnt_UnreceiveTime; // 持续多久没有接受到数据
unsigned int Cnt_UnsendTime; // TX队列有数据, 但是持续多久没有发送出去
// 串口动作检查
#define RECEIVING (1)
#define SENDING (1)
#define IDLE (0)
unsigned char Flg_RxStatusNow;
unsigned char Flg_RxStatusLast;
unsigned char Flg_TxStatusNow;
unsigned char Flg_TxStatusLast;
unsigned char Flg_Status;
#define USART_CTL_PORT_DIR (P2DIR)
#define USART_CTL_PORT_OUT (P2OUT)
#define USART_CTL_PORT_IN (P2IN)
#define PIN_USART_CTL (BIT0)
#define PIN_USART_CTL_HIGH USART_CTL_PORT_OUT |= PIN_USART_CTL
#define PIN_USART_CTL_LOW USART_CTL_PORT_OUT &= ~PIN_USART_CTL
#define PIN_USART_CTL_DOUT USART_CTL_PORT_DIR |= PIN_USART_CTL
#define PIN_USART_CTL_DIN USART_CTL_PORT_DIR &= ~PIN_USART_CTL
void Delay_ms(unsigned loop)
{
unsigned int i;
for(;loop>0;loop--)
{
for(i=0;i<50;i++);
}
}
// 向发送队列TX写一个字节的数据(用户发送使用)
_EXTERN unsigned int Queue_WriteByteToTxQueue(_IN unsigned char DataIn)
{
Flg_Status = ERR_OK;
// 存放发送数据
Queue_Tx[Queue_Tx_SavePostation] = DataIn;
// 移动指针
if (Queue_Tx_SavePostation == FIFO_TX_LENGTH-1) Queue_Tx_SavePostation = 0;
else Queue_Tx_SavePostation++;
// 检查是否溢出
if ((Queue_Tx_ReadPostation - Queue_Tx_SavePostation) <= 1)Flg_Status = ERR_TX_QUEUE_OVERFLOW;
return (Flg_Status);
}
// 从发送队列TX读取一个字节的数据(发送中断使用)
_EXTERN unsigned int Queue_ReadByteFromTxQueue(_OUT unsigned char * DataOut)
{
Flg_Status = ERR_OK;
// 检查是否有数据等待发送
if (Queue_Tx_ReadPostation == Queue_Tx_SavePostation)
{
// 没有数据等待发送
Flg_Status = ERR_TX_QUEUE_EMPTY;
*DataOut = 0;
}
else
{
// 有数据需要发送
*DataOut = Queue_Tx[Queue_Tx_ReadPostation];
// 移动指针
if (Queue_Tx_ReadPostation == FIFO_TX_LENGTH-1) Queue_Tx_ReadPostation = 0;
else Queue_Tx_ReadPostation++;
}
return (Flg_Status);
}
// 向接受队列RX写一个字节的数据(接受中断使用)
_EXTERN unsigned int Queue_WriteByteToRxQueue(_IN unsigned char DataIn)
{
Flg_Status = ERR_OK;
// 存放发送数据
Queue_Rx[Queue_Rx_SavePostation] = DataIn;
// 移动指针
if (Queue_Rx_SavePostation == FIFO_RX_LENGTH-1) Queue_Rx_SavePostation = 0;
else Queue_Rx_SavePostation++;
// 检查是否溢出
if ((Queue_Rx_ReadPostation - Queue_Rx_SavePostation) <= 1)Flg_Status = ERR_RX_QUEUE_OVERFLOW;
return (Flg_Status);
}
// 从接受队列RX读取一个字节的数据(用户读取使用)
_EXTERN unsigned int Queue_ReadByteFromRxQueue(_OUT unsigned char * DataOut)
{
Flg_Status = ERR_OK;
// 检查是否有数据等待发送
if (Queue_Rx_ReadPostation == Queue_Rx_SavePostation)
{
// 没有数据等待发送
Flg_Status = ERR_RX_QUEUE_EMPTY;
*DataOut = 0;
}
else
{
// 有数据需要发送
*DataOut = Queue_Rx[Queue_Rx_ReadPostation];
// 移动指针
if (Queue_Rx_ReadPostation == FIFO_RX_LENGTH-1) Queue_Rx_ReadPostation = 0;
else Queue_Rx_ReadPostation++;
}
return (Flg_Status);
}
// 从接受队列RX检测指定位置的数据一个字节的数据, 不影响指针位置
_EXTERN unsigned int Queue_TouchByteFromRxQueue(_IN unsigned int Positon, _OUT unsigned char * DataOut)
{
Flg_Status = ERR_OK;
// 有数据需要发送
*DataOut = Queue_Rx[Positon];
return (Flg_Status);
}
// 清空接受队列
_EXTERN void Queue_ClearRxQueue(void)
{
// 清空接受队列
Queue_Rx_ReadPostation = Queue_Rx_SavePostation;
}
// 清空发送队列
_EXTERN void Queue_ClearTxQueue(void)
{
// 清空发送队列
Queue_Tx_ReadPostation = Queue_Tx_SavePostation;
}
_EXTERN unsigned int _OUT Queue_Tx_WaitingSendBytes(void)
{
return (Queue_Tx_SavePostation - Queue_Tx_ReadPostation);
}
_EXTERN unsigned int _OUT Queue_Rx_WaitingReadBytes(void)
{
return (Queue_Rx_SavePostation - Queue_Rx_ReadPostation);
}
// 字节CRC校验函数
_OUT unsigned int Caculate_CRC16_Byte(_IN unsigned char Data, _IN unsigned int CRC)
{
unsigned char j;
CRC = CRC ^ Data; // 和当前字节异或一次
for(j=0; j<8; j++) // 循环8次
{
if(CRC & 0x01) // 判断最低位,如果为1
{
CRC = CRC >> 1; // 右移一位
CRC = CRC ^ 0xA001; // 和多相式异或
}
else // 判断最低位,如果为0
{
CRC = CRC >> 1; // 右移一位
}
}
return(CRC); // 返回到当前字节为止的CRC值
}
// 数组CRC校验函数
_OUT unsigned int Caculate_CRC16_Buff(_IN unsigned char *Data, _IN unsigned char Length)
{
unsigned int CRC = 0xffff; // CRC的初始值为FFFF
unsigned int i;
for(i=0; i<Length; i++)
{
CRC = Caculate_CRC16_Byte(Data[i], CRC); // 计算数组CRC值
}
return(CRC);
}
// 强制触发TX硬件中断
void USART_CallTxInterrupt()
{
PIN_USART_CTL_HIGH;
//PIN_USART_CTL_DOUT;
IFG2 |= UTXIFG0;
}
// 发送起始函数
_EXTERN void USART_SendInit(void)
{
// 初始化CRC寄存器
Reg_SendCRC = 0xffff;
}
// 发送字节函数
_EXTERN void USART_SendByte(_IN unsigned char ByteData)
{
Flg_Status = ERR_OK;
// 放入数据
Flg_Status = Queue_WriteByteToTxQueue(ByteData);
if (Flg_Status != ERR_OK) return; // 异常返回
// 并进行CRC校验
Reg_SendCRC = Caculate_CRC16_Byte(ByteData, Reg_SendCRC);
}
// 发送结束函数
_EXTERN void USART_SendChech(void)
{
Flg_Status = ERR_OK;
// 将CRC放入
Flg_Status = Queue_WriteByteToTxQueue(Reg_SendCRC % 256);
if (Flg_Status != ERR_OK) return; // 异常返回
Flg_Status = Queue_WriteByteToTxQueue(Reg_SendCRC / 256);
if (Flg_Status != ERR_OK) return; // 异常返回
// 强制中断, 开始发送数据
USART_CallTxInterrupt();
//Delay_ms(100);//------------------------
}
// 接受字节函数
_EXTERN unsigned int USART_ReceiveByte(_OUT unsigned char *ByteData)
{
Flg_Status = ERR_OK;
unsigned char Tmp_Data;
// 取出数据
Flg_Status = Queue_ReadByteFromRxQueue(&Tmp_Data);
if (Flg_Status != ERR_OK) return (Flg_Status); // 异常返回
*ByteData = Tmp_Data;
// !!! 这样做是危险的, 无法让调用者知道该值是否有效 !!!
return (Flg_Status);
}
// 获得接受信息的前两个字节(SlaverAddress, Function)不影响队列指针
_EXTERN unsigned int USART_ReceiveInfo(_OUT unsigned char *SlaverAddress, _OUT unsigned char *Function)
{
Flg_Status = ERR_OK;
unsigned char Tmp_Data0;
unsigned char Tmp_Data1;
// 取出数据
Flg_Status = Queue_TouchByteFromRxQueue(Queue_Rx_ReadPostation, &Tmp_Data0);
if (Flg_Status != ERR_OK) return (Flg_Status); // 异常返回
Flg_Status = Queue_TouchByteFromRxQueue(Queue_Rx_ReadPostation+1, &Tmp_Data1);
if (Flg_Status != ERR_OK) return (Flg_Status); // 异常返回
*SlaverAddress = Tmp_Data0;
*Function = Tmp_Data1;
// !!! 这样做是危险的, 无法让调用者知道该值是否有效 !!!
return (Flg_Status);
}
void USART_AutoErrorCheck(void)
{
// 自动清除RX队列, 防止错误发生影响到通讯
if (Flg_RxStatusNow == IDLE) Cnt_UnreceiveTime++; else Cnt_UnreceiveTime = 0;
if (Cnt_UnreceiveTime == ERROR_AUTO_RESET) // 30 * 15 = 450ms
{
Queue_ClearRxQueue(); // 持续500毫秒没有接收到数据, 自动清除RX队列
PIN_USART_CTL_LOW;
Cnt_UnreceiveTime = 0;
}
// 自动清除TX队列
/* if (Queue_Tx_WaitingSendBytes() != 0) Cnt_UnsendTime++; else Cnt_UnsendTime = 0;
if (Cnt_UnsendTime == ERROR_AUTO_RESET) // 30 * 15 = 450ms
{
Queue_ClearTxQueue(); // 持续500毫秒没有接收到数据, 自动清除RX队列
Cnt_UnsendTime = 0;
}
*/
}
// 串口通讯监视定时器(需要其他模块提供, 例如TA, TB等)
// 定时器的周期决定了串口响应接受事件和发送事件的快慢
// 建议定时器周期在10~100毫秒之间
_EXTERN void USART_CheckOnTimerInterrupt(void)
{
unsigned char SlaverAddress;
unsigned char Function;
// 接受判断
switch(Flg_RxStatusLast - Flg_RxStatusNow)
{
case 0x0000: // 正在接受/空闲
break;
case 0x0001: // 接受完成
if (Reg_ReceiveCRC == 0)
{
Flg_Status = USART_ReceiveInfo(&SlaverAddress, &Function);
// 接收到的数据帧CRC正确
if (SlaverAddress == Reg_MasterAddress) Flg_ReceiveData = TRUE;
else
{
Flg_ReceiveData = FALSE;
Queue_ClearRxQueue();
}
}
else
{
// 接收到的数据帧CRC错误
Queue_ClearRxQueue();
}
// 重置CRC寄存器, 未下次的接受做准备
Reg_ReceiveCRC = 0xffff;
break;
case 0xffff: // 开始接受
break;
default: // 未知
break;
}
USART_AutoErrorCheck(); // 自动错误检查和修复
// 重置标志
Flg_RxStatusLast = Flg_RxStatusNow;
Flg_TxStatusLast = Flg_TxStatusNow;
Flg_RxStatusNow = IDLE;
Flg_TxStatusNow = IDLE;
}
// 接受中断服务程序
void USART_InterruptRx(void)
{
unsigned char Tmp_Data;
Flg_Status = ERR_OK;
// 标志接受数据
Flg_RxStatusNow = RECEIVING;
Cnt_ReceiveBytes++;
// 读取数据
Tmp_Data = RXBUF0;
// 存入队列
Flg_Status = Queue_WriteByteToRxQueue(Tmp_Data);
// CRC校验
Reg_ReceiveCRC = Caculate_CRC16_Byte(Tmp_Data, Reg_ReceiveCRC);
}
// 发送中断服务程序
void USART_InterruptTx(void)
{
unsigned char Cnt_WaitingSendBytes;
unsigned char Tmp_SendData;
Flg_Status = ERR_OK;
// 标志发送数据
Flg_TxStatusNow = SENDING;
// 检查队列是否有待发数据
Cnt_WaitingSendBytes = Queue_Tx_WaitingSendBytes();
if (Cnt_WaitingSendBytes != 0)
{
// 读取一个待发数据
Flg_Status = Queue_ReadByteFromTxQueue(&Tmp_SendData);
// 发送
TXBUF0 = Tmp_SendData;
Cnt_SendBytes++;
}
else
{
PIN_USART_CTL_LOW;
// PIN_USART_CTL_DOUT;
Queue_ClearTxQueue();
}
}
void TB_Init(void)
{
// 当 TAR 的等于 CCR0的值时, CCIFG 置位
// 当 TAR 的计数值从 CCR0 计到 0时, TAIFG置位
TACTL = TASSEL_2 + TACLR + ID_0 + MC_0;
TACCR0 = TIMER_INTERVAL;
TACTL = TASSEL_1 + TACLR + ID_0 + MC_1;
TACCTL0 |= CCIE;
//_EINT();
}
// 串口硬件初始化
_EXTERN void USART_Init(void)
{
U0CTL |= CHAR; // 8-bit character
U0TCTL |= SSEL1; // UCLK = SMCLK
U0BR0 = 0x6D;
U0BR1 = 0x00;
UMCTL0 = 0x10;
U0CTL &= ~SWRST; // Initialize USART state machine
ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD ???????????????????????????????
IE1 |= URXIE0; // Enable USART0 RX interrupt
IE1 |= UTXIE0;
P2SEL |= (BIT4 + BIT5);
P2DIR |= (BIT4 + BIT5 + BIT0);
PIN_USART_CTL_LOW;
TB_Init();
}
#pragma vector = UART0RX_VECTOR
__interrupt void USART0_RXIRQ (void)
{
USART_InterruptRx();
}
#pragma vector = UART0TX_VECTOR
__interrupt void USART0_TXIRQ (void)
{
Delay_ms(16);
USART_InterruptTx();
}
/**************************************************************************************************************
// TBCCO 中断服务
#pragma vector = TIMERA0_VECTOR
__interrupt void TACC0_IRQ(void)
{
_NOP();
_NOP();
_NOP();
USART_CheckOnTimerInterrupt();
}
************************************************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -