抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

出于一些特殊原因(帮学弟做个课设),需要用到STC89C52,用都用到了,记录一下过程吧。

串口


/* UART STC89C52RC Frequency 11.0592MHz
* receive data and tranfer them back
* Created: Thursday May 26, 2022
* Processor: STC89C52RC
* Compiler: Keil μVision5
* Version: v1.0
*/

#include <reg52.h>
#include <stdio.h>

// 类型重定义,便于移植
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;

// 定义串口接收标志枚举类型
enum
{
BufEmpty = 0, // 接收缓冲区为空
BufOverflow, // 接收缓冲区溢出
BufReady, // 成功接收到结束标志符
WaitInput
} Buf_Flag; // 串口接收标志

#define BufSize 32 // 定义接收缓冲区大小为 32字节
// 定义结束符为回车符 "\r(回车符)+\n(换行符)"
#define R_SYM '\r'
#define N_SYM '\n'

// 外部可见函数声明
void uart_P3_init(void);
void uart_init(void);
void send_char(uint8_t ch);
void send_string(uint8_t *str);
void delay(uint16_t i);

// 定义串口接收缓冲区
uint8_t RXD_Buf[BufSize] = {0};

/* main 主函数*/
void main()
{
uint8_t i = 0;
Buf_Flag = BufEmpty; //接收缓冲区标志赋初值
uart_P3_init(); //初始化P3口
uart_init(); //初始化串口
ES = 0; //发送前关闭串口中断,以防发送完每个字符都没必要地进入中断程序
send_string("I am AT89C51 Serial COM1!\r\n"); //发送字符串
ES = 1; //发送完打开串口中断
while (1)
{
if (Buf_Flag == BufEmpty) //如果还没有收到COM2的数据,发送请求输入提示
{
ES = 0; //发送前关闭串口中断,以防发送完每个字符都没必要地进入中断程序
send_string("\r\nPlease input form Serial Assistant(<32Bytes)!\r\n");
ES = 1; //发送完打开串口中断
Buf_Flag = WaitInput; //请求输入提示只发送一次
}
else if (Buf_Flag == BufReady) //如果收到并存入了RXD_Buf中
{
ES = 0; //发送前关闭串口中断
send_string("Your Input: "); //提示你刚才输入了什么
send_string(RXD_Buf); // 把接收到的字符串发送回去
i = 0; // i计数清零
while (i < BufSize) //接收缓冲区清零
{
RXD_Buf[i++] = 0; //清零RXD_Buf
}
Buf_Flag = BufEmpty; //串口接收标志:空
ES = 1; //处理完打开串口中断
}
else if (Buf_Flag == BufOverflow)
{
ES = 0; //发送前关闭串口中断
send_string("ERROR:RXD_Buf is full!\r\n"); // 提示缓冲区溢出
delay(2000); //按需忽略之后再从COM2输入的内容
i = 0; // i计数清零
while (i < BufSize) //接收缓冲区清零
{
RXD_Buf[i++] = 0; //清零RXD_Buf
}
Buf_Flag = BufEmpty; //串口接收标志:空
ES = 1; //处理完打开串口中断
}
}
}

/* 延时函数 */
void delay(uint16_t i)
{
uint8_t j;
for (; i > 0; i--)
for (j = 0; j < 125; j++)
;
}

/* 串口参数配置函数,这里配置为9600波特率,1位停止位,8位数据位,无校验 */
void uart_init(void)
{
TMOD = 0x20; // Timer1以定时模式工作在方式2:8位常数自动装入定时器/计数器
SCON = 0x40; // SM0=0,SM1=1=1,方式1,10位UART "0 D0~D7 1",波特率可变
REN = 1; //允许串口接收数据位
TH1 = 0xFD; // 9600波特率:晶振的频率/(12*(256-初值))=波特率*32
TL1 = 0xFD; //方式2的TH1,TL1是相等的,TL1自动重装TH1初值
PCON = 0x00; // SMOD=0波特率不加倍
IE = 0x90; //允许总中断,允许串口中断,禁止其他中断
PS = 0; //设置串行口中断优先级
TR1 = 1; //当GATE=0,TR1置“1” 启动定时器1
}

/* P3串口初始化函数 */
void uart_P3_init(void)
{
P3 = 0x0F; // P3.0 P3.1用作串口的RXD和TXD
}

/* send_char函数, ch为待发送的字符 */
void send_char(uint8_t ch)
{
SBUF = ch; // SBUF是指串行口同地址的两个缓冲寄存器,一个是发送寄存器,一个是接收寄存器,
while (!TI)
; //等待一个字符(一帧)发送完毕
TI = 0; // TI软件清零,等待下一次发送后的置位
}
/* send_string函数, *str为待发送的字符串首元素地址 */
void send_string(uint8_t *str)
{
while (*str != '\0') //字符串里的数据发送不到结尾
{
send_char(*str); //调用字符发送函数
str++; // 指针指向下一个待发字符
}
}

/*串口中断接收数据函数 */
void uart_interrupt(void) interrupt 4
// 中断默认优先级:0外部中断0 > 1定时/计数器0 > 2外部中断1 > 3定时/计数器1 > 4串行中断;
{
static uint8_t n = 0; //一次性接收输入字符串字符个数计数,静态变量只在编译时赋一次初值
if (TI == 1) //如果是发送进入中断,中断直接返回
{
TI = 0; // TI清0
return;
}
if (RI == 1) // RI置位表示一帧数据接收完毕,RI必须用软件清0
{
RI = 0; //中断标志位清零
ES = 0; //关闭串口中断,预防而已,防止下面程序执行时被打断
if (n < BufSize - 1) // 接收缓冲区未溢出
{
RXD_Buf[n++] = SBUF; //读入的数据依次放入RXD_Buf中
if (((RXD_Buf[n - 2] == R_SYM) && (RXD_Buf[n - 1] == N_SYM))
\|| ((RXD_Buf[n - 2] == N_SYM) && (RXD_Buf[n - 1] == R_SYM)))
// 判断是否接收到结束符(回车 "\r\n"或者"\r\n")
{
Buf_Flag = BufReady; // 成功接收到带结束标志符的一串字符
RXD_Buf[n] = '\0'; // 在字符串末尾补字符数组(串)结束标识
n = 0; // n清0
}
}
else // 接收缓冲区溢出
{
Buf_Flag = BufOverflow; // 串口接收标志:溢出
n = 0; // n清0
}
ES = 1; //打开串口中断
}
}