|
LPC900 系列的串口模拟程序
ploto 发表于 2005-10-5 01:47 Philips LPC900单片机
/* 52单片机实用的IO模拟串行口C语言源程序 作者:LPC900 移植: saint(yuzhuju) 用途:短距离、波特率要求不高、环境干扰不大的场合 特点: 程序简练、实用、移植方便 占用定时器T0 只消耗约600字节的ROM 有详细的注释 参数: 晶振 :7.373MHz 波特率:2400 起始位:1 数据位:8 校验位:无 停止位:1 ----------------------- yuzhuju: 感觉程序中的HITS只有在判断开始位时,才有实际意义, 其它HITS使用场合中,如果不是每次采样都和上次结果作比较判断,意义就不是很大,只能凑个接收周期 不知道理解对不对. qizhong_zhu 在UART通讯协议中,应该是16个采样周期,在第7、8、9个采样周期中取多的一个作为实际的字符位,如两个1一个0,则是1, 两个0一个1则是0 ,主要是为了抗干扰 在此处其实是用了中间位置的一个位作为采样的位,其余7次的位都丢弃了,HITS起了这个作用。其实在这种情况下,HITS取2即可 还可以提高 波特率(不过如果HITS取2,则开始位对齐上可能就对得不齐了) ----------------------- //修改,原来的方式 使用了两个缓冲区,占用了32个字节 (好象还要多一些),这下节省了空间
发送时采用等待方式,一定要每个字节发送完后才能发送下一个 接收时采用了查询方式,主程序总是检查RI2标志,如果置位,则调用RXD_Get_Char()来接收字符
看到有人说可以收到字符后通过产生键盘中断来实现中断功能,我没有试过,有谁试成功了请告诉我 ploto_zhu@yahoo.com.cn
本程序在LPC931下测试通过,我想在900系列上应该没有问题,有问题同样请告诉我
非常感谢前人所做的工作 */
extern void Uart2Init(void);//初始化 extern void TXD_Send_String(const unsigned char s[]);//发送字符串函数
#i nclude <REG931.H>
//修改如下定义将方便程序移植 sbit RXD_pin = P0^7; //定义接收引脚 sbit TXD_pin = P0^6; //定义发送引脚 #define MAIN_CLK 7373000 //定义主频 #define BAUD_RATE 2400 //定义波特率(数值不能太高,因为要给T2中断服务程序留足执行时间) #define HITS 8 //定义采样率(应当是偶数;减少采样率能提高波特率,但为保证可靠工作,最小不能少于6次)
#define RXD_BUF_LEN 16 //定义接收缓冲区大小 volatile unsigned char RXD_buf;//[RXD_BUF_LEN]; //定义接收缓冲,RXD_buf 为接收时使用的缓冲,RXD_ch为收到后的缓冲 //在程序中使用 RXD_ch来取得字符,因为这样同时可以再接收数据 volatile bit RI2; //收到了数据标志,在主程序中不断地查询该标志 //volatile unsigned char RXD_p1; //指向缓冲区,由中断程序自动修改 //volatile unsigned char RXD_p2; //指向缓冲区,由主程序修改
#define TXD_BUF_LEN 16 //定义发送缓冲区大小 volatile unsigned char TXD_buf;//[TXD_BUF_LEN]; //定义发送缓冲区(循环队列) volatile bit TI2; //置需要发送标志,如果是1,表示发送缓冲区内容, //volatile bit TI2; //输出标志,为0表示可用,为1表示正在输出 //volatile unsigned char TXD_p1; //指向TXD_buf,由主程序修改 //volatile unsigned char TXD_p2; //指向TXD_buf,由中断程序修改
//定时器T0初始化 void Time0Init(void) { unsigned char TimeValue; TAMOD&=(~0x01);//T0M2=0 TMOD &=0xF0; //清低4位 TMOD |= 0x02; //T0GATE 0 T0C/T 0 T0M1 1 T0M0 0 /* TMOD|=0X02; //T0M1=1 TMOD&=(~0X01);//T0M0=0,T0 MODE 2 TMOD&=(~0X04);//设置为定时器功能; TMOD&=(~0X08);//设置为TR0使能定时器 */ // IP0H|=0x02;//设置T0为最高优先级中断 // IP0|=0x02; TimeValue=256 - ( MAIN_CLK / 2 ) / ( BAUD_RATE * HITS ); //定时器的CLK是MAIN_CLK/2:) //好象只能设置到2400,再低就要溢出了 TH0 = TimeValue; TL0 = TimeValue; ET0= 1; TR0 = 1; IT0=1; EA=1; //初始化接收、发送标志 // TX_OUT=0; }
//发送单个字符 void TXD_Send_Char(const unsigned char c) { TXD_buf=c; TI2=1; while(TI2);// 等待发送完毕 //在T2中断服务程序里会自动完成发送
}
char RXD_Get_Char() //取一个字符,一定要在RI等于1的时候 取,否则取得的值是前一次的值 { // while(!RI); //等待取得一个字节 ,注释掉,万一出错也不会进入死循环 RI2=0; return RXD_buf; }
void SendUART2(unsigned char *buffer,unsigned char len) { unsigned char i; for(i=0;i<len;i++) TXD_Send_Char(buffer[i]); } //发送字符串(不包括末尾的'\0') void TXD_Send_String(const unsigned char s[]) { unsigned char c; unsigned int i = 0; for (;;) { c = s[i++]; if ( c == '\0' ) break; TXD_Send_Char(c); } }
//定义接收缓冲字符 volatile unsigned char bdata RXD_ch; sbit RXD_ch_MSB = RXD_ch^7;
//定义发送缓冲字符 volatile unsigned char bdata TXD_ch; sbit TXD_ch_LSB = TXD_ch^0;
//T2中断服务程序 //每中断HITS次处理1位 //定义接收所需要的变量
static void IRQTIME0() interrupt 1 using 3 { //先清除TF2 // TF0 = 0; //接收数据 static bit RXD_doing = 0; //正在接收的标志 static unsigned char RXD_t = HITS/2; //接收时计数T2的中断次数 static unsigned char RXD_cnt; //接收时bit位的计数器 //定义发送所需要的变量 static bit TXD_doing = 0; //正在发送的标志 static unsigned char TXD_t; //发送时计数T2的中断次数 static unsigned char TXD_cnt; //发送时bit位的计数器
if( RXD_doing ) //正处于接收状态 { if( --RXD_t == 0 ) //经过了HITS个采样脉冲 { if( RXD_cnt == 0 ) //8个数据位接收完毕 { if( RXD_pin ) //检测到停止位 { RXD_buf=RXD_ch; //移入缓冲区 RI2 = 1; //置位标志位 } RXD_doing = 0; //接收全部完毕,清除正在接收的标志 RXD_t = HITS/2; //恢复RXD_t的初始值 } else //接收数据位 { RXD_ch >>= 1; RXD_ch_MSB = RXD_pin; //上面2条语句若用{CY=RXD_pin; CY=(RXD_ch&0x01); RXD_ch=ACC;}代替,效率更高 RXD_cnt--; RXD_t = HITS; } } } else //检测起始位[/#] { if ( RXD_pin ) { RXD_t = HITS/2; } else { RXD_t--; if ( RXD_t == 0 ) //连续HITS/2次采样RXD_pin都是0,就可以确认起始位 { //启动接收 RXD_t = HITS; RXD_cnt = 8; RXD_doing = 1; } } } //发送数据
if ( TXD_doing ) //正处于发送状态 { TXD_t--; if ( TXD_t == 0 ) { if ( TXD_cnt == 0 ) //发送全部完毕 { TXD_doing = 0; //清除正在发送的标志 TI2=0; //清发送标志,表示已经发送完毕 } else { if ( TXD_cnt == 1 ) //8个数据位发送完毕 { TXD_pin = 1; //发送停止位 } else //发送数据位 { TXD_pin = TXD_ch_LSB; TXD_ch >>= 1; //上面2条语句若用{CY=(TXD_ch&0x01); TXD_pin=CY; TXD_ch=ACC;}代替,效率更高 } TXD_cnt--; TXD_t = HITS; } } } else { if ( TI2 ) //如果发送缓冲队列不空 { //从发送缓冲队列中取出要发送的数据 TXD_ch = TXD_buf; //启动发送 TXD_doing = 1; TXD_cnt = 9; TXD_t = HITS; //先发送起始位 TXD_pin = 0; } else { //发送缓冲队列是空的,不发送任何数据 } }
}
//系统初始化 void Uart2Init(void) { RI2=0; //没有收到数据 TI2=0; //没有数据要发 RXD_pin =1 ; TXD_pin =1 ; Time0Init(); }
//主程序 void main(void) { char chGot; P0M1=0x00; P0M2=0x00; //设为准双向口 Uart2Init(); TXD_Send_String("The author is 21IC LPC900.\r\n"); while(1) { if(RI2) { chGot=RXD_Get_Char(); TXD_Send_Char(chGot); if(chGot == 'S') TXD_Send_String("He He ,I've found you!"); else if(chGot == 'A') SendUART2("SENDUART2",9); } }
}
|