把LPC900的串口模拟程序移植到了LPC922,很稳定
yuzhuju 发表于 2005-6-14 11:49 Philips LPC900单片机
感觉LPC900写的程序可读性很好,不像有些网友的C语言里面都偏僻语法,看上去好象很高深厉害,实际可读性一点都不好.第一次用模拟串口,感觉收发很稳定,谢谢LPC900.
/*用I/O模拟串行口例程(LPC900)
下面的程序是我以前写的,适合于80C52内核的单片机,不能直接用在LPC900系列单片机上。我现在懒了,
不想再修改,如果要用,您自己动手做一些修改吧:
首先,该程序中的定时器用的是T2,然而LPC900系列单片机中没有T2。您可以将其换成T0或者是T1。
RXD_pin和TXD_pin的属性要重新做一些设置,使之能够在您的LPC900单片机上运行。
晶振不能用22.1184MHz那么高,建议用低于12MHz的晶振或者直接使用片内RC振荡器。
*/
/*
52单片机实用的IO模拟串行口C语言源程序
作者:LPC900
移植: saint(yuzhuju)
用途:短距离、波特率要求不高、环境干扰不大的场合
特点:
程序简练、实用、移植方便
占用定时器T0
只消耗约600字节的ROM
有详细的注释
参数:
晶振 :7.373MHz
波特率:2400
起始位:1
数据位:8
校验位:无
停止位:1
-----------------------
yuzhuju:
感觉程序中的HITS只有在判断开始位时,才有实际意义,
其它HITS使用场合中,如果不是每次采样都和上次结果作比较判断,意义就不是很大,只能凑个接收周期
不知道理解对不对.
-----------------------
*/
extern void Uart2Init(void);//初始化
extern void TXD_Send_String(const unsigned char s[]);//发送字符串函数
extern void Uart2Task(void);//放在主函数WHILE(1)中,一旦收到结束符号'?',把RXD_buf中收到的数据发送回来
#i nclude <REG922.H>
//修改如下定义将方便程序移植
sbit RXD_pin = P0^4; //定义接收引脚
sbit TXD_pin = P0^5; //定义发送引脚
#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]; //定义接收缓冲区(循环队列)
volatile unsigned char RXD_p1; //指向缓冲区,由中断程序自动修改
volatile unsigned char RXD_p2; //指向缓冲区,由主程序修改
#define TXD_BUF_LEN 16 //定义发送缓冲区大小
volatile unsigned char TXD_buf[TXD_BUF_LEN]; //定义发送缓冲区(循环队列)
volatile unsigned char TXD_p1; //指向TXD_buf,由主程序修改
volatile unsigned char TXD_p2; //指向TXD_buf,由中断程序修改
volatile bit U2TEnable;
//定时器T0初始化
void Time0Init(void)
{
unsigned char TimeValue;
TAMOD&=(~0x01);//T0M2=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 ); //此公式值得你琢磨一下
//好象只能设置到2400,再低就要溢出了
TH0 = TimeValue;
TL0 = TimeValue;
ET0= 1;
TR0 = 1;
}
//接收初始化
void RXDInit(void)
{
unsigned char i;
P0M1 &= ~(0X01 << 4); //PortSet(0,4,GPIO);把P0.4设置为GPIO
P0M2 &= ~(0X01 << 4);
RXD_pin = 1;
RXD_p1 = 0;
RXD_p2 = 0;
for(i=0;i<16;i++)//RXD_BUF_LEN
{
RXD_buf[i] = 0x00;
}
}
//发送初始化
void TXDInit(void)
{
unsigned char i;
P0M1 &= ~(0X01 << 5); //PortSet(0,5,GPIO);把P0.5设置为GPIO
P0M2 &= ~(0X01 << 5);
TXD_pin = 1;
TXD_p1 = 0;
TXD_p2 = 0;
for ( i=0; i< TXD_BUF_LEN; i++ )
{TXD_buf[i] = 0x00;}
}
//发送单个字符
void TXD_Send_Char(const unsigned char c)
{
unsigned char p; //临时变量
p = TXD_p1 + 1;
if ( p >= TXD_BUF_LEN ) p = 0;
while ( p == TXD_p2 ); //判断发送缓冲队列是否已满,如果是,则暂时不能发送
TXD_buf[TXD_p1] = c; //先将c写入队列
TXD_p1 = p; //再修改TXD_p1
//在T2中断服务程序里会自动完成发送
}
//发送字符串(不包括末尾的'\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
{
//定义接收所需要的变量
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位的计数器
//先清除TF2
TF0 = 0;
//接收数据
if( RXD_doing ) //正处于接收状态
{
if( --RXD_t == 0 ) //经过了HITS个采样脉冲
{
if( RXD_cnt == 0 ) //8个数据位接收完毕
{
if( RXD_pin ) //检测到停止位
{
RXD_t = RXD_p1 + 1; //在这里,RXD_t作为临时变量
if ( RXD_t >= RXD_BUF_LEN ) RXD_t = 0;
if ( RXD_t != RXD_p2 ) //如果接收缓冲队列未满
{
RXD_buf[RXD_p1] = RXD_ch;
RXD_p1 = RXD_t;
if(RXD_ch=='?'){U2TEnable=1;}
}
else
{
//如果接收缓冲队列已满,只好丢弃新收到数据
}
}
else //检测停止位时出错
{
//舍弃新收到的数据
}
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; //清除正在发送的标志
}
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 ( TXD_p2 != TXD_p1 ) //如果发送缓冲队列不空
{
//从发送缓冲队列中取出要发送的数据
TXD_ch = TXD_buf[TXD_p2++];
if ( TXD_p2 >= TXD_BUF_LEN ) TXD_p2 = 0;
//启动发送
TXD_doing = 1;
TXD_cnt = 9;
TXD_t = HITS;
//先发送起始位
TXD_pin = 0;
}
else
{
//发送缓冲队列是空的,不发送任何数据
}
}
}
//系统初始化
void Uart2Init(void)
{
TXDInit();
RXDInit();
Time0Init();
U2TEnable=0;
}
void Uart2Task(void)
{
unsigned char c;
if(U2TEnable)
{
while ( RXD_p2 != RXD_p1 )
{
c = RXD_buf[RXD_p2++];
if ( RXD_p2 >= RXD_BUF_LEN ) RXD_p2 = 0;
TXD_Send_Char(c);
}
TXD_Send_String("Return Data Over.\r\n");
U2TEnable=0;
}
}
//主程序
void main(void)
{
Uart2Init();
TXD_Send_String("The author is 21IC LPC900.\r\n");
{
Uart2Task();
}
}
评论