⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usart.c

📁 传一个我们项目中用到得Modbus程序
💻 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 + -