/********************************************** IO 口模拟232串行异步通讯程序 (占用两个IO口及一个定时器) 本程序使用示波器校正,基本能保证在PC发过来的方波的中间位置进行取样 说明: 1位起始位,9位数据位,1位停止位 问题:1. 如果PC侧连续发数据,并且51侧收到一个字节就响应一个字节到PC, 会出现总是少发一个数据给PC的情况,如PC发 123456789,则51回 13579 但该问题不影响MDB协议的实现,故这里不讨论该问题的解决方法. 2. 如果比指定的定时器中断优先级高的中断进入,并且处理时间比较长,可能会造成接收到的数据不正确(这个问题在硬件串口中不存在) 3. 如果PC连续发数据,51收到一个数据,准备收下一个数据时,随便进入一个中断,并且处理时间过长,将会导致丢失数据或收到错误的数据(这个问题在硬件串口中也存在) **********************************************/ #include <reg52.h> #include "uart_sim.h"
sbit BT_REC =P3^0; sbit BT_SND =P3^1; sbit P1_0 =P1^0; #define ETx ET1 #define TRx TR1 #define TFx TF1 #define THx TH1 #define TLx TL1 #define PTx PT1
#define StartBitOn() (BT_REC==0) #define UART_SIM_THx (256-208) #define UART_SIM_THx_HALF (256-22) //9600bps 就是 1000000/9600=104.167微秒 执行的
//时间是104.167*11.0592/12 = 96 (补偿数= 原数/2 - (原数/2)*(5/12)=(96/2)-(96/2)*(4/5)=?)
//时间是104.167*24.0/12=208.33=208 (补偿数= 原数/2 - (原数/2)*(5/12)=(208/2)-(208/2)*(4/5)=22) //如果有问题可以将4/5改为3/4或2/3
//时间是104.167*22.1184/12 =192 (补偿数= 原数/2 - (原数/2)*(5/12)=(192/2)-(192/2)*(4/5)=20)
#define UART_SIM_TIMER_ENABLE do{TLx=THx; TRx=1;}while(0)//TRx = 1,启动Timer
#define UART_SIM_TIMER_DISABLE TRx=0 #define UART_SIM_TIMER_THx(x) do{THx = (x);TLx=THx;}while(0)
#define TRUE 1 #define FALSE 0
#define F_SEND 1 #define F_RECV 0 typedef unsigned char UINT8; typedef bit BOOL; typedef bit BIT1;
//************** 全局变量 for uart_sim begin
BOOL fSendOrRecv; //F_SEND F_RECV
BOOL fRecvSuccess; //TRUE or FALSE, 如果没有正确的接收到停止位,则置 FALSE
BOOL fRecvStartbit; //TRUE 表示接收起始位, false 表示接收数据位或停止位
UINT8 sendOrRecvLen; //要发送/或接收的数据的BIT数
UINT8 sendOrRecvByte; //要发送/或接收到的字符
BIT1 bitMode; //************** 全局变量 for uart_sim end
//定时器计数器1的中断
void UART_SIM_TIMER_Interrupt() interrupt 3 //Timer1
{ P1_0 = !P1_0; //输出一个脉冲用于校正取样点
if(fSendOrRecv==F_RECV){
if(fRecvStartbit){ UART_SIM_TIMER_THx(UART_SIM_THx); fRecvStartbit = FALSE; return; } if(sendOrRecvLen>1){ sendOrRecvByte>>=1; if(BT_REC) { sendOrRecvByte|=0x80; } --sendOrRecvLen; } else if(sendOrRecvLen==0) { //接收 stop
fRecvSuccess = BT_REC; //停止定时器
UART_SIM_TIMER_DISABLE; } else { //接收 mode
bitMode = BT_REC; --sendOrRecvLen; }
} else { if(fRecvStartbit){ fRecvStartbit=FALSE; //停止定时器
UART_SIM_TIMER_DISABLE; return; } if(sendOrRecvLen>1){ BT_SND = (bit)(sendOrRecvByte&0x01); sendOrRecvByte>>=1; --sendOrRecvLen; } else if(sendOrRecvLen==0){ //发送 stop
BT_SND = 1; fRecvStartbit=TRUE; } else { //发送 mode
BT_SND = bitMode; --sendOrRecvLen; } } }
void uart_sim_sendByte(UINT8 b, bit mode){ UART_SIM_TIMER_THx(UART_SIM_THx); UART_SIM_TIMER_ENABLE; //记数器0启动
BT_SND = 0; //启动位
fSendOrRecv = F_SEND; fRecvStartbit=FALSE;
sendOrRecvLen = 9; sendOrRecvByte = b; bitMode = mode;
while(sendOrRecvLen); while(TRx); }
BOOL uart_sim_recvByte(UINT8* pbyte, UINT8* pmode){ while(!StartBitOn()); fSendOrRecv = F_RECV; fRecvStartbit = TRUE; //置跳过起始位
UART_SIM_TIMER_THx(UART_SIM_THx_HALF); UART_SIM_TIMER_ENABLE; //记数器0启动
sendOrRecvLen = 9;
while(sendOrRecvLen); *pbyte = sendOrRecvByte; *pmode = bitMode; while(TRx); return fRecvSuccess; } void uart_sim_init(){ //TMOD=0x22; /*定时器1为工作模式2(8位自动重装),0为模式2(8位自动重装) */
//如果使用T0,则应该是 TMOD=(TMOD&0xf0)|0x02;
//如果使用T1,则应该是 TMOD=(TMOD&0x0f)|0x20;
TMOD=(TMOD&0x0f)|0x20;
//PCON=00;
PCON &=0x7F; //SET SMOD=0;
TRx=0; //在发送或接收才开始使用
TFx=0; THx=UART_SIM_THx; TLx=THx; ETx=1;//定时器/记数器T1的溢出中断允许位,ET,允 许中断
PTx = 1; //设定定时器x为高优先级
}
void test_send_nostop(){ while(1){ uart_sim_sendByte(0x55,1); uart_sim_sendByte(0xaa,1); uart_sim_sendByte(0xff,1); uart_sim_sendByte(0x0f,1); uart_sim_sendByte(0xf0,1); uart_sim_sendByte(0x00,1); } }
void test_send2(){ UINT8 i; static const char code a[]="#define UART_SIM_TIMER_ENABLE do{TL0=TH0; TR0=1;}while(0);//TR0 = 1"; for(i=0; i<sizeof(a)/sizeof(char); ++i) uart_sim_sendByte(a[i], 1); }
UINT8 idata recvbuf[50]; UINT8 idata recvmodebuf[50]; void test_recv2(){ UINT8 * p = recvbuf; UINT8 * pm = recvmodebuf; UINT8 i=10; while(i--){ if(!uart_sim_recvByte(p, pm)){ *p = 0xee; } ++p; ++pm; }
i=10; p=recvbuf; pm=recvmodebuf; while(i--){ uart_sim_sendByte(*p,1); uart_sim_sendByte(*pm,1); ++p; ++pm; } }
void test_send_recv(){ UINT8 Getch, mode; while(1) { if(uart_sim_recvByte(&Getch, &mode)){ uart_sim_sendByte(Getch, 1); } else { uart_sim_sendByte(0xee, 1); } } }
char code c512[3] _at_ 0x3b; void main() { uart_sim_init();
EA=1;
test_send2();
test_recv2();
test_send_recv();
test_send_nostop(); }
|