蓝桥杯15单片机--串口通信模块

目录

一、计算机常用通信方式

二、串口通信UART ·

三、串口通信寄存器

(1)串行口1控制寄存器SCON和PCON

​(2)串行口1数据缓冲器SBUF

(3)串行口1辅助寄存器AUXR

(4)串行口1中断相关寄存器

四、程序设计

(1)串口程序生成

(2)发送多个字符程序 

(3)串口中断程序

五、程序源码

(1)指令是一个字符串

(2)指令是多个字符串,进行判断之后,返回不同数据

(3)按键按下,返回数据

关于sprintf函数


一、计算机常用通信方式

计算机常用通信方式有两种:并行通信和串行通信

并行通信概述:

·多条数据线同时传送数据的每一位。

·其特点是:传送速度快,但所需数据线多,适用于近距离通信。

    相当于对整个P1口进行赋值

串行通信概述:

通过单条数据线一位一位按顺序传送数。

其特点是:传送速度慢,但仅需一条数据线,故适用于远距离通信;

·串行通信有两种方式:异步串行通信和同步串行通信;

根据串行数据的传输方向,可以将通信分为:单工,半双工,双工

左图:并行;右图:串行

二、串口通信UART ·

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART。在UART上追加同步方式的序列信号,被称为USART(Universal Synchronous Asynchronous Receiver Transmitter)。

·异步通信的发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,互不同步(UART,1-WIRE)。

同步通信则要求发送端和接受端共同使用一个时钟信号(SP1,IIC)。

Serial port: serial interface. Usually referred to as: serial port communication, refers to the use of the serial interface of the microcontroller for data transmission.

Pay attention to distinguish the concepts of serial communication and serial port :

Serial communication : refers to a kind of communication concept. The three types of bus communication learned earlier are all serial communication, which is half-duplex, and serial port communication is full-duplex. Another classification: UART and single-bus communication protocols belong to asynchronous communication, and SPI and IIC protocols belong to synchronous communication.

Serial port : serial interface, specifically refers to a few pins on the microcontroller that can support the communication method of UART.

Overview of USB to serial port: USB to serial port is to realize the conversion between the computer USB interface and the general serial port. It provides a fast channel for computers without a serial port, and using a USB-to-serial device is equivalent to turning a traditional serial device into a plug-and-play USB device.

UART communication protocol: As a kind of asynchronous serial communication protocol, UART works by transmitting each character of the transmitted data one by one.

Important parameters of serial communication: baud rate, data bits, stop bits and parity. Parity bit: Represents how many 1s or 0s there are in the previous data, and the other party also checks after receiving the data

3. Serial communication register

Each serial port consists of 2 data buffers SBUF, a shift register, a serial control register and a baud rate generator .

The data buffer SBUF of each serial port is composed of 2 mutually independent receiving and sending buffers, which can send and receive data at the same time.

The sending buffer SBUF can only be written but not read, and the receiving buffer SBUF can only be read but not written, so the two buffers can share one address code.

(1) Serial port 1 control registers SCON and PCON

SMOD0 bit: It is 0 at the initial power-on, don't worry about it.

Usually only use mode 1 and 9 bits in mode 3: one more parity bit.

Multi-machine communication: communication between multiple microcontrollers

(2) Serial port 1 data buffer SBUF

(3) Serial port 1 auxiliary register AUXR

Timer 0 cannot be used as a baud rate generator

(4) Serial port 1 interrupt related registers

4. Programming

(1) Serial port program generation

   1-STC-ISP software → baud rate calculator;

   2-Select the serial port number, data bits, baud rate generator, and timer clock used;

   3- Select the system clock frequency;

   4- Set the baud rate;

   5- Generate C code;

[Note]: This is only the serial port initialization code and the timing has started, but there is no serial port-related interrupt permission, and the general interrupt is not enabled.

(2) Send multiple character programs 

void UART_TX(unsigned char *p)//发送数据函数,发送数组的话,这里就要定义一个指针 应用于:单片机向电脑发送数据
{
	unsigned char index=0;
	
	do
	{
		SBUF=p[index++];
		while(TI == 0);//一直为0,数据还没发送完
		TI = 0;//发送完之后,由用户置0
	}
	while(p[index]!=0);	
}

(3) Serial interrupt program

Judgment is made on the input serial port command, if it is correct, it meets the following requirements. 

void UART1() interrupt 4   //串口1中断
{
	RI=0;//由用户将RI置0
	RX = SBUF;
	if(RX == '$')//应用于:电脑向单片机发送数据。单片机判断接收到的是否是这个字符,用单引号;如果判字符串,用双引号
	{
		P2=0X80;P0=0XFE;
	}
	else if(RX == '&')
	{
		P2=0X80;P0=0XFF;
	}	
}

ES=1; Open serial interrupt

Special reminder: When processing the format of the sent data, ASCII codes are commonly used for conversion, and the corresponding table is as follows:

5. Program source code

(1) The instruction is a string

Program requirements: send serial port command: "STAD\r\n", return "ONE" received

#include <STC15F2K60S2.H>
#include <stdio.h>

#define uchar unsigned char
#define uint unsigned int
	
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uchar Smg_num=0;
uchar Smg[]={0,7,10,5,6,10,1,2};

sbit TX = P1^0;
sbit RX = P1^1;

unsigned char TX_chuankou[] = "USART TEST PROGRAM\r\n";//定义一个数组,发送一组数据
//unsigned char TX[] = {0x01,1,2,3};//这种方式与上面的区别:
//第一种定义如果里面有数字的话,会把里面的数字转换成它所对应的 ASCII码值,然后再转换成对应的二进制发送出去
//第二种直接将数字转换成二进制发送出去
unsigned char RX_chuankou[6];

uchar receive_num=0,chuanshu_shuju=0;
uchar receive_tt=0; 
bit receive_over=0;

void Allinit();
void Delayms(uint ms);
void Timer2Init(void);		//1毫秒@11.0592MHz
void UartInit(void);
void UART_TX(unsigned char *p);

void main()
{
	Allinit();
	Timer2Init();
	UartInit();
	ES=1;EA=1;
	while(1)
	{
		if(chuanshu_shuju==1)//查询数据指令
		{
			sprintf((char*)TX_chuankou,"ONE\r\n");
			UART_TX(TX_chuankou);
			chuanshu_shuju=0;receive_over=0;receive_num=0;
		}
	}
}

void UART1() interrupt 4   //串口1中断
{
	if(RI)//RI 不为0
	{
		RX_chuankou[receive_num] = SBUF;
		receive_num++;
		receive_tt=1;//每接收到一次数据,就让接收计时变量置1.
		RI=0;//由用户将RI置0
	}
	
	if(receive_over==1)//数据接收完成之后 进行判断
	{
		if((RX_chuankou[0]=='S')&(RX_chuankou[1]=='T')&(RX_chuankou[2]=='A')&(RX_chuankou[3]=='D')&(RX_chuankou[4]=='\r')&(RX_chuankou[5]=='\n'))
		{
			chuanshu_shuju=1;
		}
	}
}

void UART_TX(unsigned char *p)//发送数据函数,发送数组的话,这里就要定义一个指针 应用于:单片机向电脑发送数据
{
	unsigned char index=0;
	
	do
	{
		SBUF=p[index++];
		while(TI == 0);//一直为0,数据还没发送完
		TI = 0;//发送完之后,由用户置0
	}
	while(p[index]!=0);	
}

void UartInit(void)		//[email protected]
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器时钟1T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xC7;		//设置定时初始值
	TH1 = 0xFE;		//设置定时初始值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
}

void timer2() interrupt 12
{
	P2|=0XC0;
	P2&=0XDF;
	P0=(1<<Smg_num);
	P2|=0XE0;
	P2&=0XFF;
	P0=tab[Smg[Smg_num]];
	if(++Smg_num==8) Smg_num=0;
	
	if(receive_tt>=1)
	{
		receive_tt++;
		if(receive_tt>=30)
		{
			receive_tt=0;
			receive_over=1;// 置1 代表接收数据完毕
		}
	}
}

void Timer2Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0xCD;		//设置定时初始值
	T2H = 0xD4;		//设置定时初始值
	AUXR |= 0x10;		//定时器2开始计时
	
	IE2|=0X04;EA=1;
}

void Allinit()
{
	P2=0XA0;P0=0X00;
	
	P2=0X80;P0=0XFF;
	
	P2=0XC0;P0=0XFF;
	P2=0XE0;P0=0XFF;
}

void Delayms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
	for(j=845;j>0;j--);
}

(2) The instruction is multiple character strings, and different data will be returned after judgment

Program requirements: send serial port command: "ST\r\n", return "ONE" received; send serial port command: "AAA", return received "TWO"; other are error commands, return "ERROR".

#include <STC15F2K60S2.H>
#include <stdio.h>

#define uchar unsigned char
#define uint unsigned int
	
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uchar Smg_num=0;
uchar Smg[]={0,7,10,5,6,10,1,2};

sbit TX = P1^0;
sbit RX = P1^1;

unsigned char TX_chuankou[] = "USART TEST PROGRAM\r\n";//定义一个数组,发送一组数据
//unsigned char TX[] = {0x01,1,2,3};//这种方式与上面的区别:
//第一种定义如果里面有数字的话,会把里面的数字转换成它所对应的 ASCII码值,然后再转换成对应的二进制发送出去
//第二种直接将数字转换成二进制发送出去
unsigned char RX_chuankou[4];

uchar receive_num=0,chuanshu_shuju=0;
uchar receive_tt=0; 
bit receive_over=0;

void Allinit();
void Delayms(uint ms);
void Timer2Init(void);		//1毫秒@11.0592MHz
void UartInit(void);
void UART_TX(unsigned char *p);

void main()
{
	Allinit();
	Timer2Init();
	UartInit();
	ES=1;EA=1;
	while(1)
	{
		if(chuanshu_shuju==1)//查询数据指令
		{
			sprintf((char*)TX_chuankou,"ONE\r\n");
			UART_TX(TX_chuankou);
			chuanshu_shuju=0;receive_over=0;receive_num=0;
		}
		else if(chuanshu_shuju==2)//查询参数指令
		{
			sprintf((char*)TX_chuankou,"TWO\r\n");
			UART_TX(TX_chuankou); 
			chuanshu_shuju=0;receive_over=0;receive_num=0;
		}
		else if(chuanshu_shuju==3)//错误指令
		{
			sprintf((char*)TX_chuankou,"ERROR\r\n");
			UART_TX(TX_chuankou);
			chuanshu_shuju=0;receive_over=0;receive_num=0;
		}
	}
}

void UART1() interrupt 4   //串口1中断
{
	if(RI)//RI 不为0
	{
		RX_chuankou[receive_num] = SBUF;
		receive_num++;
		receive_tt=1;//每接收到一次数据,就让接收计时变量置1.
		RI=0;//由用户将RI置0
	}
	
	if(receive_over==1)//数据接收完成之后 进行判断
	{
		if((RX_chuankou[0]=='S')&(RX_chuankou[1]=='T')&(RX_chuankou[2]=='\r')&(RX_chuankou[3]=='\n'))
		{
			chuanshu_shuju=1;
		}
		else if((RX_chuankou[0]=='A')&(RX_chuankou[1]=='A')&(RX_chuankou[2]=='A'))
		{
			chuanshu_shuju=2;
		}
		else chuanshu_shuju=3;
	}
}

void UART_TX(unsigned char *p)//发送数据函数,发送数组的话,这里就要定义一个指针 应用于:单片机向电脑发送数据
{
	unsigned char index=0;
	
	do
	{
		SBUF=p[index++];
		while(TI == 0);//一直为0,数据还没发送完
		TI = 0;//发送完之后,由用户置0
	}
	while(p[index]!=0);	
}

void UartInit(void)		//[email protected]
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器时钟1T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xC7;		//设置定时初始值
	TH1 = 0xFE;		//设置定时初始值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
}

void timer2() interrupt 12
{
	P2|=0XC0;
	P2&=0XDF;
	P0=(1<<Smg_num);
	P2|=0XE0;
	P2&=0XFF;
	P0=tab[Smg[Smg_num]];
	if(++Smg_num==8) Smg_num=0;
	
	if(receive_tt>=1)
	{
		receive_tt++;
		if(receive_tt>=30)
		{
			receive_tt=0;
			receive_over=1;// 置1 代表接收数据完毕
		}
	}
}

void Timer2Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0xCD;		//设置定时初始值
	T2H = 0xD4;		//设置定时初始值
	AUXR |= 0x10;		//定时器2开始计时
	
	IE2|=0X04;EA=1;
}

void Allinit()
{
	P2=0XA0;P0=0X00;
	
	P2=0X80;P0=0XFF;
	
	P2=0XC0;P0=0XFF;
	P2=0XE0;P0=0XFF;
}

void Delayms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
	for(j=845;j>0;j--);
}

(3) Press the button to return the data

 Program requirements: press S4, return to receive "ONE". This requirement was tested in the mock question 1 of the 14th provincial competition. The method is very simple, just set a flag.

#include <STC15F2K60S2.H>
#include <stdio.h>

#define uchar unsigned char
#define uint unsigned int
	
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uchar Smg_num=0;
uchar Smg[]={0,7,10,5,6,10,1,2};

sbit TX = P1^0;
sbit RX = P1^1;

unsigned char TX_chuankou[] = "USART TEST PROGRAM\r\n";//定义一个数组,发送一组数据
//unsigned char TX[] = {0x01,1,2,3};//这种方式与上面的区别:
//第一种定义如果里面有数字的话,会把里面的数字转换成它所对应的 ASCII码值,然后再转换成对应的二进制发送出去
//第二种直接将数字转换成二进制发送出去
unsigned char RX_chuankou[6];

uchar receive_num=0,chuanshu_shuju=0;
uchar receive_tt=0; 
bit receive_over=0;

void Allinit();
void Delayms(uint ms);
void Keyscan();
void Timer2Init(void);		//1毫秒@11.0592MHz
void UartInit(void);
void UART_TX(unsigned char *p);

void main()
{
	Allinit();
	Timer2Init();
	UartInit();
	ES=1;EA=1;
	while(1)
	{
		ifif(chuanshu_shuju==1)//查询数据指令
		{
			sprintf((char*)TX_chuankou,"ONE\r\n");
			UART_TX(TX_chuankou);
			chuanshu_shuju=0;receive_over=0;receive_num=0;
		}
		
		Keyscan();
		//Delayms(5);
	}
}

void UART1() interrupt 4   //串口1中断
{

}

void UART_TX(unsigned char *p)//发送数据函数,发送数组的话,这里就要定义一个指针 应用于:单片机向电脑发送数据
{
	unsigned char index=0;
	
	do
	{
		SBUF=p[index++];
		while(TI == 0);//一直为0,数据还没发送完
		TI = 0;//发送完之后,由用户置0
	}
	while(p[index]!=0);	
}

void UartInit(void)		//[email protected]
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器时钟1T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xC7;		//设置定时初始值
	TH1 = 0xFE;		//设置定时初始值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
}

void timer2() interrupt 12
{
	P2|=0XC0;
	P2&=0XDF;
	P0=(1<<Smg_num);
	P2|=0XE0;
	P2&=0XFF;
	P0=tab[Smg[Smg_num]];
	if(++Smg_num==8) Smg_num=0;
	
	if(receive_tt>=1)
	{
		receive_tt++;
		if(receive_tt>=30)
		{
			receive_tt=0;
			receive_over=1;// 置1 代表接收数据完毕
		}
	}
}

void Keyscan()
{
	if(P32==0)
	{
		Delayms(5);
		if(P32==0)
		{
			Smg[2]=3;
		}
		while(!P32);
	}
	
	else if(P33==0)
	{
		Delayms(5);
		if(P33==0)
		{
			if(chuanshu_shuju==0) {chuanshu_shuju=1;}
		}
		while(!P33);
	}
}

void Timer2Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0xCD;		//设置定时初始值
	T2H = 0xD4;		//设置定时初始值
	AUXR |= 0x10;		//定时器2开始计时
	
	IE2|=0X04;EA=1;
}

void Allinit()
{
	P2=0XA0;P0=0X00;
	
	P2=0X80;P0=0XFF;
	
	P2=0XC0;P0=0XFF;
	P2=0XE0;P0=0XFF;
}

void Delayms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
	for(j=845;j>0;j--);
}

About the sprintf function

For the sprintf function used in serial communication, you can check out my article:

​​​​​​The sprintf() function in C51 uses _keil sprintf function usage_Haohao fighting! Blog-CSDN Blog 

Guess you like

Origin blog.csdn.net/ChenWenHaoHaoHao/article/details/130297932