@comzyh
2015-07-03T21:16:30.000000Z
字数 4107
阅读 2005
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 states
rINTPND = 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);
// 设置定时器配置寄存器0
rTCFG0 = 0; // 预分频数值 为 0
// 设置定时器配置寄存器1
rTCFG1 = 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();
else
OUT_TXD_L();
NewTxData >>= 1;
nCountTxData ++;
}
}
ExitCritical(&r);
}
GPG0 收到下降沿信号(起始位,代表对方开始发送),启动接收定时器
接收定时器(Timer3)周期为波特率对应信号周期的一半
在第3,5,7,9,11,13,15,17次定时器触发时取值,可避开起始位(第一次触发)和边沿信号(偶数次)
//timer3 接收时钟 接收管脚 GPH3
void VirUart_Rx_TimerInit(int baud)
{
int time_cnt;
// int time_Prescaler1 = 0; // 预分频
//int samples = 10; // 采样数
// 计算计数常数
time_cnt = PCLK / (1 * 2) / (baud * 2);
// 设置定时器配置寄存器0
rTCFG0 = 0; // 预分频数值 为 0
// 设置定时器配置寄存器1
rTCFG1 = 0; // 分割器值 为 0 1/2PLCK
// 设置计数器
rTCNTB3 = time_cnt;
// 设置控制寄存器
rTCON = (rTCON & (~(0x1f << 16))) | (0x02 << 16); // 更新 TCNTB2
rTCON = (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))); //关闭 TCNTB3
NewRxData = 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; // 设置接收未处理标志位0
NewFlagTx = 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 ;