访问电脑版页面

导航:老古开发网手机版其他

8XC196单片机串行口的C语言编程

导读:
关键字:
8XC196单片机串行口的C语言编程 河北科技大学王晓君张 英唱春来 摘要以8XC196KC工作于串行口方式1为例,给出基于Tasking C196 v5.0的C源程序,充分展示了用高级语言编程灵活、易维护的优点,对于196单片机串行口的编程,具有重要的参考价值。 关键词8XC196单片机串行口C语言 196系列单片机串行口相对于96系列增加了一些功能,在SFR中增加了相应的控制及状态位。在196单片机中串行发送和接收有了各自的中断矢量,另外波特率的计算方法也有所不同。 一、 串行口初始化函数和常、变量的定义 在用C196编写串行口程序之前,一定要对硬件有充分的了解。与串行口操作有关的SFR包括:串行口控制寄存器sp_con、串行口状态寄存器sp_stat、缓冲器sbuf、波特率寄存器baud_rate。与串行口中断有关的寄存器有int_pend1和int_mask1。有关控制寄存器有ioc1,其第5位决定是使用TXD功能还是P2.0功能。当然,其中最重要的是sp_con和sp_stat。它们的地址均为11H,其定义如下(其中X代表未定义的位,为与将来版本兼容应写为0): 7〖〗6〖〗5〖〗4〖〗3〖〗2〖〗1〖〗0X〖〗X〖〗X〖〗TB8〖〗REN〖〗PEN〖〗M2〖〗M1TB8:设置发送时的第9位数据,发送完成后被清零。当使用奇偶校验时此位无效。 REN:使能接收(此时P2.1不再作普通I/O口)。 PEN:使能奇偶校验(偶校验)。 M2,M1:设置串行口工作方式:方式0=00;方式1=01;方式2=10;方式3=11。 7〖〗6〖〗5〖〗4〖〗3〖〗2〖〗1〖〗0RB8/RPE〖〗RI〖〗TI〖〗FE〖〗TXE〖〗OE〖〗X〖〗XRB8/RPE:使用奇偶校验功能时,出现奇偶校验错时置1;否则为接收的第9位数据。 RI,TI:接收与发送完成标志。 FE:帧出错标志(未发现有效的停止位时被置位)。 TXE:发送器空标志(此时可传送2个字节)。 OE:接收溢出错标志(接收缓冲器中前1个字节被读之前,在移位寄存器中的数据又被装载到接收缓冲器中,置OE标志)。 下面给出含有与串行口操作有关的外部变量及常量定义的C源程序。 #pragma model(kc)/*使用KC系列*/ #include #include /*包含有与KC有关的头文件*/ #pragma interrupt(Receive=25,Transmit=24) /*定义函数Receive()和Transmit()为中断服务函数,编译器在地址2032H(=2000H+25*2)和2030H(=2000H+24*2)单元处自动填加两函数的中断向量*/ #define TRANSMIT_BUF_MAX_SIZE 20 /*定义接收缓冲区的最大长度*/ #define RECEIVE_BUF_MAX_SIZE 20 /*定义发送缓冲区的最大长度*/ #define FREQUENCY 16000000L /*定义所用时钟频率 */ #define BAUDRATE 9600/*定义所用的波特率*/ #define BAUD_REG_VALUE ((unsigned int) (FREQUENCY/((long)BAUDRATE*16)-1)+ 0x8000) /*按波特率计算公式计算出所需的寄存器值。注意最高位必须设为1,以表示使用XTAL1分频*/ #define RI_BIT 0x40 #define TI_BIT 0x20/*TI,RI的位操作字节*/ unsigned char sp_stat_image; /*sp_stat的映像单元,由于sp_stat中各状态位,在读sp_stat后要被清零*/ unsigned char Trans_Buf\[TRANSMIT_BUF_MAX_SIZE\]; /*定义发送缓冲区*/ unsigned char Rece_Buf\[RECEIVE_BUF_MAX_SIZE\]; /*定义接收缓冲区*/ char Begin_Trans_Buf,End_Trans_Buf; /*定义发送缓冲区的头、尾索引*/ char Begin_Rece_Buf,End_Rece_Buf; /*定义接收缓冲区的头、尾索引*/ 下面给出串行口初始化函数,系统在每次上电初始化时调用该函数。 void InitilizeSerialPort(void)/*串行口初始化函数*/ { unsigned char wsr_image=wsr;/*保存窗口*/ wsr=0;/*切换到0窗口*/ baud_rate=(unsigned char)(BAUD_REG_VALUE); baud_rate=(unsigned char)(BAUD_REG_VALUE>>8); /*设置波特率寄存器,连续装载2个字节,先装低字节*/ sp_con=0x09; /*串行工作于方式1,允许接收,不使能奇偶校验功能*/ sp_stat_image=sp_stat TI_BIT; /*关键一句,以启动发送*/ Begin_Trans_Buf=End_Trans_Buf=0; Begin_Rece_Buf=End_Rece_Buf=0;/*各索引归零*/ int_mask1=0x03;/*允许发送和接收各自中断*/ enable();/*开总中断*/ wsr=wsr_image;/*恢复窗口*/ } 程序中给出若干宏定义,可根据实际使用情况灵活更改。此外还为串行口的发送与接收定义了各自的缓冲区(大小可根据实际情况而变)及相应的首尾索引(为简化操作,这里没有使用指针)。为了能在所有的函数中都能对缓冲区进行操作,将它们定义为全局的。 二、 串行口中断服务函数 由于中断服务函数不能被其他函数调用,故该函数不能有参数,也不能有返回值。在接收中断服务中,先检查缓冲区是否已满。如未满,则将sbuf中的内容存入当前尾索引所指的接收缓冲区中。 void Receive(void) { wsr=0; sp_stat_image =sp_stat; /*将串行口状态读入sp_stat_image中*/ /*在此处填加判断sp_stat_image的各个状态位和相应OPE、FE、OE出错的处理程序*/ if(End_Rece_Buf+1==Begin_Rece_Buf (End_Rece_Buf==RECEIVE_BUF_MAX_SIZE-1&&!Begin_Rece_Buf)) { /*接收缓冲区已满,在此处加入错误处理程序*/ } else { if(++End_Rece_Buf>RECEIVE_BUF_MAX_SIZE-1) End_Rece_Buf=0; /*修正尾索引*/ Rece_Buf\[End_Rece_Buf\]=sbuf;/*将sbuf数据存入缓冲区*/ } sp_stat_image&=(~RI_BIT); } 在发送中断中,首先判断发送缓冲区中是否有待发送数据。如有,则将当前头索引所在数据发送,然后修正头索引。 void Transmit(void) { wsr=0; sp_stat_image =sp_stat;/*将串行口状态读入sp_stat_image中*/ if(Begin_Trans_Buf!=End_Trans_Buf)/*判断是否有待发送数据,如没有则返回*/ { sbuf=Trans_Buf\[Begin_Trans_Buf\];/*发送当前头索引所在发送缓冲区的数据*/ if(++Begin_Trans_Buf>TRANSMIT_BUF_MAX_SIZE-1) Begin_Trans_Buf=0;/*修正头索引*/ sp_stat_image&=(~TI_BIT); } } 三、 字符发送与接收函数 观察以上程序可知,中断服务程序已将串行口发送与接收“封装”在底层。它“自动”对缓冲区中数据进行操作,能“自动”修正索引,并能处理传送中出现的错误。主程序中,只与发送与接收缓冲区发生关系即可。通过对缓冲区进行不同操作,可以实现不同的发送与接收功能。下面给出类似于标准C语言中的putchar()与getchar()的字符读写函数Putchar()和Getchar()。 Getchar()由串行口读回1个字符 unsigned char Getchar() { while(Begin_Rece_Buf==End_Rece_Buf);/*没有输入字符,则等待*/ if(++Begin_Rece_Buf>RECEIVE_BUF_MAX_SIZE-1) Begin_Rece_Buf=0;/*修正索引*/ return(Rece_Buf\[Begin_Rece_Buf\]);/*返回头索引所在接收缓冲区内的字符*/ } Putchar()函数向串行口发送1个字符 void Putchar(unsigned char c)/*C中为要发送的字符*/ { while((Begin_Trans_Buf==End_Trans_Buf+1) (End_Trans_Buf==TRANSMIT_BUF_MAX_SIZE-1&&!Begin_Trans_Buf));/*如发送缓冲区已满,则等待*/ Trans_Buf\[End_Trans_Buf\]=c;/*将字符置入发送缓冲区*/ if(++End_Trans_Buf>TRANSMIT_BUF_MAX_SIZE-1) End_Trans_Buf=0;/*修正索引 */ if(sp_stat_image&TI_BIT) int_pend1 =0x01;/*人为产生发送中断,以启动发送过程*/ } 可见,这2个函数实际只是对串行口缓冲区操作。要注意的是TI和RI标志在函数间的传递与保护,尤其是对TI的操作,影响到发送过程的“可持续性”,要更加注意。 最后,为让读者有一总体概念,给出一示意主函数。 #deinfe TRUE 1 void main() { char c; InitilizeSerialPort(); while(TRUE) { Putchar(Getchar()); } } 它的功能就是进行从串行口读入1字节数据,然后再发送出去的循环。MES 参考文献 8XC196 C Compiler Manual,Tasking Corporation
来源:单片机与嵌入式系统应用   作者:河北科技大学 王晓君 张英 唱春来  2006/2/12 0:00:00
栏目: [ ]

相关阅读

安森美推出新的高功率图腾柱PFC控制器,满足具挑战的能效标准

动态功耗低至60μA/MHz!助力设备超长续航,首选国民技术低功耗MCU!