一、概述:
STC8H系列是带有多个串口的单片机,关于单片机串口的通信原理,不在本文的探讨的范围,本文重点讨论串口8位可变波特率模式的使用。8位可变波特率要正常工作需要使用一个定时器产生波特率,而且每个串口对应的定时器是有一规定的,当然通常定时器T2作为专用波特率发生器,4个串口都能使用。关于串口的使用,串口的端口不是完全固定的,比如说串口1默认与USB共用一个输入端,在使用串口时可能PSW1寄存器改变默认端口,每个串口都一套独立的寄存器,相关之间无串扰,当然在一定条件下可以共用一个波特率发生器T2。以下的例程,设置串口1从P36、P37输出、串口2从P46、P47输出,两个串口共用T2作为波特率发生器,实现串口1发送数据从串口2输出,串口2发送数据从串口1输出。
二、知识链接:
1、串口1控制器SCON
SM0和SM1控制串口1的工作方式:
与PC通信,8位数据可变波特率,无数据校验,选用模式1。
REN位置1允许接收控制位。
2、串口1辅助寄存器AUXR
其中S1ST2位:置0表示选用T1作为波特率发生器,置1选用T2作为波特率发生器,这里我们选t2作波特率发生器。
3、串口2控制器S2CON
S2SM0控制串口2的工作方式,当选用0时工作在8位数据可变波特率,无数据校验。S2REN,位置1允许串口2接收控制位。串口2默认使用T2作为波特率发生器。
三、实验平台搭建:
1、MCU:STC-打狗棒系列核心实验板 V2.3
2、实验板平台:德飞莱LY-51s
3、硬件连接表:
K1------>P20 发送字符
LED1----->P00 指示灯1,按键K1按钮键指示
LED2----->P01 指示灯2,串口收发指示
串口1----->P46、P47 串口1
串口2----->P36、P37 串口2
四、测试源代码:
#include <STC8H.h>
#include "intrins.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
sbit Led1=P0^0;
sbit Led2=P0^1;
sbit Led3=P0^2;
sbit Led4=P0^3;
u8 TX1_Cnt; //U1发送计数
u8 RX1_Cnt; //U1接收计数
bit B_TX1_Busy; //U1发送忙标志
u8 RX1_Buffer[16]; //u1接收缓冲
u8 TX2_Cnt; //U2发送计数
u8 RX2_Cnt; //U2接收计数
bit B_TX2_Busy; //U2发送忙标志
u8 RX2_Buffer[16]; //u2接收缓冲
void Delay1ms(unsigned char x);//当主时钟频率为12M,1ms延时为基准
void init_IO();//初始化IO
void init_Uart1();//串口1初始化
void init_Uart2();//串口2初始化
void Uart1Send(char dat);
void Uart2Send(char dat);
void Uart1SendStr(char *puts);//发送数据
void Uart2SendStr(char *puts);//发送数据
void main()
{
P_SW2 |= 0x80; //扩展寄存器XFR访问使能
init_IO();
init_Uart1();
init_Uart2();
EA=1;
Uart1SendStr("STC8H TEST!");
Uart2SendStr("STC8H TEST!");
while(1)
{
if(P20==0)
{
Delay1ms(1);
if(P20==0)
{
Uart2SendStr("STC8H TEST!");
Uart1SendStr("STC8H TEST!");
Led1=~Led1;
}
}
}
}
void init_IO()
{
RSTCFG=0x50; //开启RST键进入ISP模式
P0M1 = 0x00; P0M0 = 0x00; //设置P0口为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置P0口为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置P1口为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置P3口为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置P4口为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置P5口为准双向口
//P4M1=0xc0;P4M0=0x00;//设置P47和46高阻
}
void init_Uart1()//波特率11.0592
{
P_SW1|=0x40;//将串口1的引脚切换至P36、P37
SCON=0x50;//模式1,8位可变
T2L = 0xE8; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR|=0x04; //开启T1定时器1T工作模式
AUXR|=0x10; //开启T1定时器T1R=1
AUXR|=0x01; //Uart1使用模式1时,指定T2波特率发生器
ES=1;
B_TX1_Busy = 0;//忙检测
TX1_Cnt = 0;//发送计数
RX1_Cnt = 0;//接收计数
}
void init_Uart2()//波特率11.0592
{
S2CON=0x10; //打开允许接收
T2L = 0xE8; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR|=0x04; //开启T2定时器1T工作模式
AUXR|=0x10; //开启T2定时器T2R=1
IE2|=0x01;//开启ES=1
P_SW2|=0x01;//串口2脚位切换,将串口2脚位切换到P46、P47,默认P10、P11
B_TX2_Busy = 0;//忙检测
TX2_Cnt = 0;//发送计数
RX2_Cnt = 0;//接收计数
}
void Uart2Send(char dat)//u2发送单字符
{
while(B_TX2_Busy);
B_TX2_Busy=1;
S2BUF=dat;
}
void Uart1Send(char dat)//U1发送单字符
{
while(B_TX1_Busy);
B_TX1_Busy=1;
SBUF=dat;
}
void Delay1ms(unsigned char x) //@12.000MHz
{
unsigned char i, j;
i = 16;
j = 147;
while(x--)
{
do
{
while (--j);
} while (--i);
}
}
void Uart2SendStr(char *puts)//U2发送字符串
{
while(*puts)
{
Uart2Send(*puts++);
}
}
void Uart1SendStr(char *puts)//U1发送字符串
{
while(*puts)
{
Uart1Send(*puts++);
}
}
void UART2_isr (void) interrupt 8//Uart2串口中断入口
{
Led2=~Led2;
if((S2CON & 1) != 0)
{
S2CON &= ~1; //Clear Rx flag
RX2_Buffer[RX2_Cnt++] = S2BUF;
RX2_Cnt&=0x0f;
SBUF=S2BUF;//发送至串口2
}
if((S2CON & 2) != 0)
{
S2CON &= ~2; //Clear Tx flag
B_TX2_Busy = 0;
}
}
void UART1_isr (void) interrupt 4//Uart2串口中断入口
{
Led2=~Led2;
if((SCON & 1) != 0)
{
SCON &= ~1; //Clear Rx flag
RX1_Buffer[RX1_Cnt++] = SBUF;
RX1_Cnt&=0x0f;
S2BUF=SBUF;//发送至串口1
}
if((SCON & 2) != 0)
{
SCON &= ~2; //Clear Tx flag
B_TX1_Busy = 0;
}
}