一切发送和接收的过程都是在后台完成的,具体实现需要一个带捕获&匹配功能的定时器,本实现用的是TIM1。任意具有捕获输入功能的引脚都可以用作接收引脚,任意GPIO引脚都可以用作发送引脚。此实现用TIM_CH4作为发送引脚,TIM1_CH3作为接收引脚。
整个数据传输过程基于定时器1的溢出事件,溢出周期为发送半个bit的时间,这是因为发送和接收用的是同一个定时器。
发送环节:
当有数据字节进入发送缓存后,发送请求标志被置位,最近的一个事件更新中断用于启动此次发送传输,从产生发送请求到开始发送的最长延时为一个溢出周期。在每个偶数的溢出中断中设置相应的发送引脚的电平。
接收环节:
空闲状态下,CH3一直处于输入捕获状态,当捕获到第一个下降沿时(起始位),此时计数器的值会自动保存到CCR3中用于之后的匹配,在捕获中断中将通道模式改为匹配,同时禁止该引脚的捕获/匹配功能,使其成为普通的GPIO引脚,以便检测输入电平。由于半个bit周期的溢出事件存在,所以最近的一次匹配肯定出现在起始位的中间点,此时读取引脚上的电平,以得到该位的逻辑,之后丢弃偶数次的匹配中断,在奇数次匹配中断中读取剩余的位的值,知道接收到完整的一字节数据(包括停止位),将通道模式改为捕获,等待下一字节。
具体实现代码如
#define BAUDRATE_SWUART (1200)
#define USR_OVF_ONLY (0x04)
#define TIM1_CR_CEN (0x01) //定时器4计数使能
#define TIM1_SR_UIF (0x01)
#define TIM1_SR_CC3IF (0x08)
#define UPDATE_INTER_ENABLE (0x01)
#define CAP_COMP_INTER_ENABLE3 (0x08)
#define CHANN3_INPUT_TI3FP3 (0x01)
#define CHANN3_OUTPUT (0xFC)
#define CHANN3_FUNC_MASK (0x03)
#define CHANN3_CAP_COMP_ENABLE (0x01)
#define CHANN3_CAP_COMP_DISB (0xFE)
#define CAP_FALL_EDGE (0x02)
#define START_BIT_POS (0x01) //起始位位置
#ifdef HAVE_PARITY
#define WORD_LENGTH (11) //1个起始位,8个数据位,1个奇偶校验位,1个停止位
#define SET_RCV_BIT (0x400)
#define STOP_BIT_POS (0x200) //停止位位置
#define CHECK_BIT_POS (0x100)
#else
#define WORD_LENGTH (10)
#define SET_RCV_BIT (0x200)
#define STOP_BIT_POS (0x100)
#endif
#define BIT_MASK (0x01)
#define EVEN_CHECK (0)
/*
*********************************************************************************************************
* GLOBAL VARIABLES
*********************************************************************************************************
*/
bool IsFirstBit;
bool TxByteReady;
bool IsOdd;
uint8_t TxBitCnt; //发送位数计数
uint8_t RxBitCnt;
uint16_t TxByte; //移位发送缓存
uint16_t RxByte;
/*
*********************************************************************************************************
* Description: Swuart初始化
*
* Arguments : none
*
* Returns : none
*
* Notes : 1200
*********************************************************************************************************
*/
void InitSwuart (void)
{
TIM1->ARRH = (F_MASTER / (BAUDRATE_SWUART * 2)) >> 8;
TIM1->ARRL = (uint8_t)(F_MASTER / (BAUDRATE_SWUART * 2));
TIM1->CR1 = USR_OVF_ONLY; //仅计数器溢出才产生更新事件
TIM1->CCMR3 = CHANN3_INPUT_TI3FP3;
TIM1->CCER2 = CHANN3_CAP_COMP_ENABLE | CAP_FALL_EDGE;
TIM1->IER = UPDATE_INTER_ENABLE |CAP_COMP_INTER_ENABLE3;
TIM1->CR1 = TIM1_CR_CEN;
SwuartTxByte(0xFF); //初始化后第一个发送的第一个字节要丢弃
}
/*
*********************************************************************************************************
* Description: 发送一个字节
*
* Arguments : byte: 待发送的字节
*
* Returns : none
*
* Notes : none
*********************************************************************************************************
*/
void SwuartTxByte (uint8_t byte)
{
TxByte = byte;
TxBitCnt = WORD_LENGTH;
TxByte |= STOP_BIT_POS; //添加停止位
#ifdef HAVE_PARITY
if (GetParity(byte, EVEN_CHECK)){
TxByte |= CHECK_BIT_POS;
}
#endif
TxByte = TxByte << START_BIT_POS; //添加起始位
TxByteReady = true;
IsFirstBit = true;
}
/*
*********************************************************************************************************
* Description: 发送数据
*
* Arguments : data: 指向待发送数据的指针
* len: 数据长度
*
* Returns : none
*
* Notes : none
*********************************************************************************************************
*/
void SwuartSend (const uint8_t *data , uint8_t len)
{
uint8_t i;
static uint8_t SwuartSendBuf[50];
for (i = 0; i < len; i++){
SwuartSendBuf[i] = data[i];
}
i = 0;
while (len--){
SwuartTxByte(SwuartSendBuf[i++]);
while (TxByteReady){
;
}
}
}
/*
*********************************************************************************************************
* Description: 奇偶校验
*
* Arguments : byte: 待校验的字节
* parity: 校验类型选择
*
* Returns : none
*
* Notes : 校验位的值
*********************************************************************************************************
*/
#ifdef HAVE_PARITY
uint8_t GetParity (uint8_t byte, uint8_t parity)
{
uint8_t i;
uint8_t n;
uint16_t data;
data = byte;
n = 0;
if (data){
do{
i = data & 0x01;
if ( i > 0 ){
n++;
}
data = data >> 1;
} while ( data > 0 ) ;
}
n = n & 0x01;
if (parity){ //奇校验
if(n){
return 0;
} else {
return 1;
}
} else { //偶校验
if(n){
return 1;
} else {
return 0;
}
}
}
#endif
#pragma vector = TIM1_OVF_IRQn
__interrupt void Uart_Tx_Timing (void)
{
static uint8_t OvfInterCnt;
TIM1->SR1 &= ~TIM1_SR_UIF;
if (!TxByteReady){
return;
}
if (IsFirstBit){
OvfInterCnt = 0;
IsFirstBit = false;
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』