C51串口通信实验

串口通信

​ STC89C52(下面简称C51)系列单片机内部集成了一个功能很强的全双工串行通信口,与传统8051单片机的串口完全兼容。设有两个互相独立的接收、发送缓存器,可以同时发送和接收数据。发送缓存器只能写入不能读出,接收缓存器只能读出不能写入,两个缓存器共用一个地址吗(99H)。

​ 串行通信外设有4种工作方式,其中两种方式的波特率是可变的,另两种是固定的,以供不同应用场合选用。波特率由内部定时器/计数器产生,用软件设置不同的波特率和选择不同的工作方式。

​ C51系列单片机串行口对应的引脚是P3.0(RxD)和P3.1(TxD)。

串行口控制寄存器

C51系列单片机的串行口设有两个控制寄存器:SCON(串行控制寄存器)和PCON(波特率选择特殊功能寄存器)

SCON

串行控制寄存器

SM0和SM1共同确定串行的工作方式:

串行口的工作方式

SM2:允许方式2或方式3多机通信控制位 REN:允许/禁止串口接收控制位,REN=1为允许接收 TB8: 在方式2或方式3,为要发送的第九位数据,按需要由软件置位或清0 RB8: 在方式2或方式3,是接收到的第九位数据 TI: 发送中断请求标志位 RI: 接收中断请求标志位

​ 串行通信的中断请求:当一帧发送完成,内部硬件自动置位TI,即TI=1,请求中断处理;当接收完一帧信息时,内部硬件自动置位RI,即RI=1,请求中断处理

PCON

image-20241118205150283

PCON只有高2位(B6、B7)是属于串口的

SMOD: 波特率选择位 SNOD0: 帧错误检测有效控制位

串行口工作模式1:8位UART,波特率可变

image-20241118205618209

实验

  • P32和P33各接一个按键S3、S4。按下S3发送字符“1”到PC机,按下S4发送字符“2”到PC机的按键。-
  • PC机用串口助手软件将接收数据显示。
  • 晶振11.0592MHz,串行口用方式1,波特率9600bps
  • 接收PC发来的数据,在P1口上显示
  • 用LCD1602液晶屏显示接收到的数据

代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#include <reg52.h>


sbit E	 = P2^6;
sbit RS = P2^4;
sbit RW = P2^5;

sbit S1 = P3^0;
sbit S3 = P3^2;
sbit S4 = P3^3;

#define 	 LCD_Data 			P0


unsigned char flag1 = 1;
unsigned int time0 = 0;
unsigned int time1 = 0;

unsigned char S1_flag0 = 1;
unsigned char S1_flag1 = 1;

unsigned char S3_flag0 = 1;
unsigned char S3_flag1 = 1;

unsigned char S4_flag0 = 1;
unsigned char S4_flag1 = 1;

unsigned char clean_flag0 = 0;
unsigned char usart_send_flag1 = 0;
unsigned char usart_send_flag2 = 0;

unsigned char Addr = 1;

unsigned char LCD_flag0 = 0;

unsigned char Num = 1;



void LCD_Delay(unsigned char time)
{		
		while(time--)
		{
			unsigned char i = 0;
			for(i = 0; i<123;i++);
		}
}

void LCD_WriteCom(unsigned char com)
{		

		RS = 0;
		RW = 0;
		LCD_Data = com;
		E = 1;
		LCD_Delay(1);
		E = 0;
		LCD_Delay(1);
}


void LCD_WriteData(unsigned char Data)
{	
		RS = 1;
		RW = 0;
		LCD_Data = Data;
		E = 1;
		LCD_Delay(1);
		E = 0;
		LCD_Delay(1);
}

void LCD_Init(void)
{
		LCD_WriteCom(0x38);	//设置16x2显示,5x7点阵,8位数据接口
		LCD_WriteCom(0x0C);	// 0000 1100
		LCD_WriteCom(0x06);	//0000  0110
		LCD_WriteCom(0x01);	//清除 复位

}

void LCD_SetCursor(unsigned Line, unsigned char Column)
{
		if(Line == 1)
		{
			LCD_WriteCom(0x80|(Column - 1));
		}
		else
		{
			LCD_WriteCom(0x80|(Column) + 0x40);
		}
		
	
}



void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned char Num)
{
		LCD_SetCursor(Line, Column);
		LCD_WriteData('0' + Num);

}

void Uart_SendByte(unsigned char Byte)
{
		SBUF = Byte;
		while(TI == 0);
		TI = 1;

}
//11.0592Mhz
void Uart_Init(void)
{
		SCON = 0x50;		//8位数据,可变波特率   
		PCON &= 0x7F;	//不使能波特率倍速位
		TMOD &= 0x0F;	//清除定时器1模式
		TMOD |= 0x20; //设定定时器1为8位自动重装
		
		TL1 = 0xFD;		//设定定时初值
		TH1 = 0xFD;		//设定定时器重装值
		ET1 = 0;	//不需要进中断
		TR1 = 1;  //启动定时器1
	
		ES = 1;	//串口中断
	
}



			



void Time_Init(void)
{
		EA = 1;
		TMOD = 0x01;
		ET0 = 1;
		TR0 = 1;
		
		TH0 = 64535 / 256;
		TL0 = 64535 % 256;

}



void main(void)
 {

		LCD_Init();
		Time_Init();
		Uart_Init();
		
	 


		while(1)
		{
			if(Addr == 17)
			{
				
				Addr = 0x41;				
			}
			
			if(usart_send_flag1 == 1)
			{
					Uart_SendByte('1');
					LCD_ShowNum(1, Addr++, 1);
					usart_send_flag1 = 0;
			}
			
			if(usart_send_flag2 == 1)
			{
					Uart_SendByte('2');
					LCD_ShowNum(1, Addr++, 2);
					usart_send_flag2 = 0;
			}
			
			if(LCD_flag0 == 1)
			{		
					LCD_ShowNum(1, Addr++, Num - '0');
					LCD_flag0 = 0;
			}
			
			if(clean_flag0 == 1)
			{		
					Addr = 1;
					LCD_WriteCom(0x01);
					clean_flag0 = 0;
			}
	
		}


 	
}	
 


 
void Time0_IT(void) interrupt 1
{
	time0 ++;
	time1 ++;
	TH0 = 45535/256;
	TL0 = 45535%256;
	
	if(time0 == 25)
	{	
		if(flag1 == 0)
		{
			flag1 = 1;
		}
		else if(flag1 == 1)
		{
			flag1 = 0;
		}
		
		time0 =0;
	}
	
	if(time1 == 1)	//非阻塞按键扫描
	{
			S1_flag1 = S1_flag0;	//保存上一次的值
			S1_flag0 = S1;				//获取新的值
		
			S3_flag1 = S3_flag0;	//保存上一次的值
			S3_flag0 = S3;				//获取新的值
		
			S4_flag1 = S4_flag0;	//保存上一次的值
			S4_flag0 = S4;				//获取新的值
		
			if(S1_flag1 == 1 && S1_flag0 == 0)
			{
					clean_flag0 = 1;
			}
			
			if(S3_flag1 == 1 && S3_flag0 == 0)
			{
					usart_send_flag1 = 1;
			}
			
			if(S4_flag1 == 1 && S4_flag0 == 0)
			{
					
					usart_send_flag2 = 1;
			}
			
			time1 = 0;
	
	}


}


void Uart_Read() interrupt 4
{
		if(RI == 1)
		{

				Num = SBUF;
				LCD_flag0 = 1;
				RI = 0;
		}

}

现象

image-20241118210050108

22324
使用 Hugo 构建
主题 StackJimmy 设计