@comzyh
2015-07-03T13:16:30.000000Z
字数 4107
阅读 2172
Author : 张永辉
[TOC]
使用GPIO_H 中的两个引脚作为串口通信RX 和 TX端
数据读写宏定义:
#define OUT_TXD_H() (rGPHDAT |=(1<<2))#define OUT_TXD_L() (rGPHDAT &=~(1<<2))#define GET_RXD_PIN() (rGPHDAT &(0X08))
由于GPH并没有外部中断功能,我们将GPH3和GPG0并联,利用GPG0的EINT8探测RX的下降沿启动接受
虚拟串口初始化函数:
/*VirUsart_init 模拟串口初始化函数参数:_baud 波特率_stop_bit 停止位 0 = 无, 1 = 有_parity_check 奇偶校验 0 = 无, 1 = 奇校验, 2 = 偶校验_data_width 数据位*/void VirUsart_init(int _baud,int _stop_bit,int _parity_check,int _data_width){baud = _baud;stop_bit = _stop_bit;parity_check = _parity_check;data_width = _data_width;VirUartGPIO_init();}
接口初始化函数
void VirUartGPIO_init(void){// 模拟管脚 配置rGPHCON = 0;rGPHCON |= (0x01 << 4); // GPH2 (TXD0) 输出 GPH3(RXD0) 输入rGPHUP |= (1 << 2) | (1 << 3);OUT_TXD_H(); // TXD0 高//GPG0 EINT8 配置rGPGCON = rGPGCON & (~0x1) | 0x2; //GPGCON[1:0] = 10//EINT8 下降沿触发rEXTINT1 = rEXTINT1 & (~0x4) | 0x2 ;//EXTINT1[2:0] = 01//设置中断服务程序pISR_EINT8_23 = (U32)VirUart_RX_ISR;//清空 EINTPEND中断请求rEINTPEND = 0xffffff;rSRCPND = BIT_EINT8_23; //to clear the previous pending statesrINTPND = BIT_EINT8_23;//取消EINT8 中断屏蔽rEINTMASK &= ~(1 << 8);rINTMSK = ~(BIT_EINT8_23);}
发送由时钟Timer2控制,时钟初始化函数如下
//timer2 发送时钟void VirUart_Tx_TimerInit(){int time_cnt;// 计算计数常数time_cnt = PCLK / (1 * 2) / (baud);// 设置定时器配置寄存器0rTCFG0 = 0; // 预分频数值 为 0// 设置定时器配置寄存器1rTCFG1 = 0; // 分割器值 为 0 1/2PLCK// 设置计数器rTCNTB2 = time_cnt;// 设置控制寄存器rTCON &= ~(0x1f << 12);rTCON |= (0xb << 12);rTCON &= ~(2 << 12);rINTPND = rINTPND; // 清零rINTMSK &= ~BIT_TIMER2; // 打开 Timer2 中断pISR_TIMER2 = (U32)Time2_Tx_Ir;}
数据发送函数
// 模拟发送数据void VirUartTxData_task(void){static unsigned char sendnum = 0;static short check;static short mask;int i;switch (flagTx){case 0: // 初始化flagTx = 1;break;case 1: // 等待起始信号if (NewFlagTx > 0){mask = (1 << data_width) - 1;flagTx = 2;VirUart_Tx_TimerInit();nCountTxData = 0;if (parity_check) // 计算校验位{check = NewTxData & mask;for (i =0; i< data_width - 1; i ++)check = (check >> 1) ^ (check & 0x1);if (parity_check == 1) // 奇校验check ^= 0x1;NewTxData |= check << data_width;}OUT_TXD_L(); // 发送一个低电平 作为起始信号}break;case 2:break;case 3: // 发送完了flagTx = 1;NewFlagTx = 0;Delay( 100 ) ;NewFlagTx = 1;NewTxData = sendnum;sendnum += 3;break;}}
Timer2的中断服务程序(实际发送程序)
void __irq Time2_Tx_Ir(void){U32 r;EnterCritical(&r);if (rINTPND == BIT_TIMER2){ClearPending(BIT_TIMER2);if (nCountTxData >= data_width + (parity_check > 0)) // 发送完成{flagTx = 3;rINTMSK |= BIT_TIMER2; // 关闭 Timer2 中断rTCON = (rTCON & (~(0x1f << 12))); //关闭 TCNTB2}else{if (NewTxData & 0x01)OUT_TXD_H();elseOUT_TXD_L();NewTxData >>= 1;nCountTxData ++;}}ExitCritical(&r);}
GPG0 收到下降沿信号(起始位,代表对方开始发送),启动接收定时器
接收定时器(Timer3)周期为波特率对应信号周期的一半
在第3,5,7,9,11,13,15,17次定时器触发时取值,可避开起始位(第一次触发)和边沿信号(偶数次)
//timer3 接收时钟 接收管脚 GPH3void VirUart_Rx_TimerInit(int baud){int time_cnt;// int time_Prescaler1 = 0; // 预分频//int samples = 10; // 采样数// 计算计数常数time_cnt = PCLK / (1 * 2) / (baud * 2);// 设置定时器配置寄存器0rTCFG0 = 0; // 预分频数值 为 0// 设置定时器配置寄存器1rTCFG1 = 0; // 分割器值 为 0 1/2PLCK// 设置计数器rTCNTB3 = time_cnt;// 设置控制寄存器rTCON = (rTCON & (~(0x1f << 16))) | (0x02 << 16); // 更新 TCNTB2rTCON = (rTCON & (~(0x1f << 16))) | (0x09 << 16); // 设置Timer2 自动加载 并启动// rINTPND |=BIT_TIMER3; // 清零rINTPND = rINTPND; // 清零rINTMSK &= ~BIT_TIMER3; // 打开 Timer2 中断pISR_TIMER3 = (U32)Time3_Rx_Ir;}
EINT8 中断代表GPG0,GPH3 收到下降沿,开始读取工作
void __irq VirUart_RX_ISR(void){VirUart_Rx_TimerInit(); //启动接收定时器RxData = 0; // 清空数据nCountRxData = 0;Timer3_Tick = 0; // Timer3 Tick 数清零}
Timer3 在 Timer3_Tick = 3,5,7,9...时接收数据
下面代码完成了数据的接收
void __irq Time3_Rx_Ir(void){U32 r;EnterCritical(&r);if (rINTPND == BIT_TIMER2){ClearPending(BIT_TIMER2);Timer3_Tick ++;if (Timer3_Tick >= 3 && (Timer3_Tick & 0x1)) // 在Tick 3,5,7,9....时接收数据{if(nCountRxData>=data_width + (parity_check > 1)) // 接收完成{//flagRx = 3;rINTMSK |= BIT_TIMER3; // 关闭 Timer3 中断rTCON = (rTCON &(~(0x1f<<16))); //关闭 TCNTB3NewRxData = RxData & (1 << data_width); // 接收数据并不需要校验位NewFlagRx = 1; //指示接收数据完成}else{if (GET_RXD_PIN()&0x01){RxData=RxData | (1 << (data_width + (parity_check > 1)));}RxData >>=1;nCountRxData ++;}}}ExitCritical(&r);}
本程序实现RS323 Echo 功能,即在RX(GPH3)接收到的字符直接经TX(GPH2)经RS232发回.
下面列出main函数主要部分
VirUsart_init(19200, 8, 1, 0); //19200bps,8位数据,1位停止位,无校验while (1){if (NewFlagRx){NewTxData = NewRxData; //将接收到的数据存储NewFlagRx = 0; // 设置接收未处理标志位0NewFlagTx = 1; // 设置未发送标志VirUartTxData_task(); // 发送字符}}
提供了虚拟串口程序的接口定义
void VirUartTxData_task(void);void VirUsart_init(int _baud, int _data_width, int _stop_bit, int _parity_check);extern volatile unsigned char NewFlagTx ;extern volatile unsigned short NewTxData ;extern volatile unsigned char NewFlagRx ;extern volatile unsigned short NewRxData ;