单片机学习(串口通信——老师的三道题)

第一题

1.STC15F2K60S2 上的串口接收任意字符串内容,直到 e 为止,接收到 e 就把接收到的内容发送出去(除了 e),在串口调试助手上打印出来。例如:STC15 串口接收到了 “1234qwsa”,不会在串口上打印出来信息。但如果 STC15 串口接收到了 “pauitydsertt”,那么就会把 “pauityds” 在串口调试助手上打印出来。

代码

//uart.c

#include "sys.h"

//字符串输出
void uart1_sendstring(u8* str){
	while(*str != '\0'){ //当输出到'\0'时,停止输出
		SBUF = *str ++;
		while(!TI);      //当TI为1时跳出循环,即输出完毕时跳出循环
		TI = 0;
	}
}

//串口初始化
void UART_Init(void){
	SCON = 0x50;
	T2H = (65536-3E6/9600)/256;  //9600波特率
	T2L = (u16)(65536-3E6/9600)%256;
	AUXR &= 0xF7;               // 定时器2定时器模式
	AUXR |= 0x15;               //允许定时器2运行,定时器2不分频,定时器2作为波特率发生器
	ES = 1;
	EA = 1;
}

void UART(void) interrupt 4{
	static u16 i = 0;
	if(RI){
		RI = 0;                  //接收完毕,软件清零
		BUF[i] = SBUF;           //接收数据,并存储到u8类型BUF数组里。
		if(BUF[i ++] == 'e')     //当接收到'e'时
		{
			BUF[i] = '\0';       //使得当前位置为'0'
			flag = 1;            //falg置一
			i = 0;
		}
	}	
  if(TI)TI = 0;	                 //软件清零
}

//main.c

#include <STC15F2K60S2.H>
#include "sys.h"
#include <string.h>

u8 BUF[100];
u8 flag;
void main(){
	All_Init();
	UART_Init();
	while(1){
		if(flag == 1){   //当flag为1
			uart1_sendstring(BUF);   //输出BUF数据
            memset( BUF , 0 , ( 100 * sizeof(u8) ) );//清零BUF数组
			flag = 0;  //清零flag
		}
	}
} 

//sys.h

#ifndef ___SYS_H_
#define ___SYS_H_

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

#ifndef u8
#define u8 unsigned char
#endif

#ifndef u16
#define u16 unsigned int
#endif

//sys.c
void All_Init(void);  //单片机初始化函数,大家都知道是什么,就不加上去了。

//uart.c
extern u8 BUF[100];      //定义外部变量
extern u8 flag;
void uart1_sendstring(u8* str);
void UART_Init(void);

#endif

要点
1、把发送函数写在中断外面,用一个flag来判断是否发送。因为发送数据需要一定时间,而中断是要快进快出的。
2、烧入程序时,记得把频率调成12MHz(因为写的定时器初始值是12MHz的)。
3、记得把数组清零,不然下一次输出会把上次没输出的字符串一起输出。
4、注意memset函数的格式。

参考博客
1、@Reage–——C 语言数组清空的几种方法比较
2、 @面包呢 ——memset

第二题

2. 自定义一个协议:数据格式为 “0xAA 0xBB dat1 dat2 dat3 dat1+dat2+dat3”,把这个协议的发送端和接收端代码都实现出来。

代码

uart.c

//第二题:
#include "sys.h"
void UART_Init(void){
	SCON = 0x50;
	T2H = (65536-3E6/9600)/256;
	T2L = (u16)(65536-3E6/9600)%256;
	AUXR &= 0xF7;
	AUXR |= 0x15;
	ES = 1;
	EA = 1;
}

void uart1_sendstring(u8* str){
	while(*str != '\0'){
		SBUF = *str ++;
		while(!TI);TI = 0;
	}
}

void UART() interrupt 4
{
	static u8 num = 0;    //存储位数
	static u8 step = 0;   //逻辑步
	if(RI)
	{
		 RI = 0;
		 switch(step)       
		 {
			 case 0:{
				   BUF[num] = SBUF;
					 if(BUF[num ++] == 0xAA)step = 1;//接收第一个数据,若为0xAA,则进入下一逻辑步
					 else num = 0;
			 }break;
			 case 1:{
  				 BUF[num] = SBUF;
					 if(BUF[num ++] == 0xBB)step = 2; //接收第二个数据,若为0xBB,则进入下一逻辑步
				 else {step = 0;num = 0;}//负责返回逻辑步0
			 }break;
			 case 2:{
				 BUF[num ++] = SBUF;//接收剩余数据
				 if(num == 6){   
						BUF[6] = BUF[2] + BUF[3] + BUF[4];
						if(BUF[5] == BUF[6])//当第六个数据为前三个数据之和
						{
						  BUF[6] = '\0';//则让第七个数据为停止位
						  flag = 1;//置一flag
						  num = 0;//清零num
			   	  }else {step = 0;num = 0;}//否则返回逻辑步0
		      }
			 }break;
      }
    }
	if(TI)TI = 0;
}


main.c

#include <STC15F2K60S2.H>
#include "sys.h"
#include <string.h>

u8 BUF[10];
u8 flag;
void main(){
	All_Init();
	UART_Init();
	while(1){
		if(flag == 1){
			uart1_sendstring(BUF);
            memset( BUF , 0 , ( 10 * sizeof(u8) ) );
			flag = 0;
		}
	}
} 

sys.h

#ifndef ___SYS_H_
#define ___SYS_H_

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

#ifndef u8
#define u8 unsigned char
#endif

#ifndef u16
#define u16 unsigned int
#endif

//sys.c
void All_Init(void);

//uart.c
extern u8 BUF[10];
extern u8 flag;
void uart1_sendstring(u8* str);
void UART_Init(void);

#endif

要点
1、存储数组要为 unsigned char 类型,因为当数据大于256时 char 类型会变成负数。
2、该写 else 的地方记得要写上!!!

参考博客
1、@关注我,优秀你 ——51 单片机自定义串口协议实现握手

第三题

3. 使用普通的 IO 口实现 uart 的发送和接收功能。
(提示用定时器,做出来会对 uart 理解得更加深刻)

代码

uart.c

#include "sys.h"
void Timer0_Init(void)             //定时器0初始化
{
  AUXR |= 0x80;
  TMOD &= 0xF0;
  TH0=(65536 - 1250)/256;          //12,000,000 / 9600 = 1250
  TL0=(65536 - 1250)%256;          
  TR0=0;               
  TF0=0;                  
  ET0 = 1;
  EA = 1;
}
                                
//检验波特率计数           
void uart_scan(void)    
{                 
     while(!flag);                 //当flag为1时,跳出循环
     flag=0;                       //清零flag
}

//发送字符
void uart_show(u8 str)
{
     u8 i=8;
     TR0=1;                        //开始计数
     P31=(bit)0;                   //发送起始位
     uart_scan();                  //等待一个位的时间
	
     while(i--)                    //发送8位数据位
     {
       P31=(bit)(str & 0x01);      //先传低位
       uart_scan();                //等待一个位的时间
       str = str >> 1;             //字符右移一位
     }
		 
     P31=(bit)1;                   //发送结束位
     uart_scan();                  //等待一个位的时间
     TR0=0;                        //停止计数
}




u8 uart_get(void){                 //接收一个字符
	 u8 str_get = 0;
	 u8 i = 8;
	 if(P30 == 0){                 //起始位
	  TR0=1;                       //启动Timer0
	  uart_scan();                 //等过起始位
	  while(i--){	               //接收8位数据位 
	 	  str_get >>= 1;
	 	  if(P30)str_get |=0x80;   //先收低位
		  uart_scan();             //等待一个位的时间
	  }
	  TR0=0;                       //停止Timer0
	  flag_show = 1;               //置一flag_show
	} 
	 return str_get;
}


void Timer0(void) interrupt 1{
	flag = 1;                      //每计数一个位的时间,使得flag为1
}



void All_Init(void){               //单片机初始化
	P0 = 0xFF;
	P2 = P2 & 0x1F | 0x80;
	P2 = P2 & 0x1F | 0xE0;
	P2 &= 0x1F;
	
	P0 = 0x00;
	P2 |= 0xA0;
	P2 &= 0x1F;
}

main.c

#include "sys.h"

u8 flag = 0;
u8 flag_show = 0;
u8 str;
void main(){
  Timer0_Init();
  All_Init();
	while(1){
		str = uart_get();
		if(flag_show == 1){
			uart_show(str);
			flag_show = 0;
		}
	}
}

sys.h

#ifndef ___SYS_H_
#define ___SYS_H_

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

#ifndef u8
#define u8 unsigned char
#endif

#ifndef u16
#define u16 unsigned int
#endif

//sys.c
extern u8 flag;
extern u8 flag_show;
void Timer0_Init(void);
void uart_show(u8 str);
void uart_scan(void);
u8 uart_get(void);
void All_Init(void);


#endif

要点:
1、注意9600波特率所需要的计数时间。
2、注意用位变量bit,如果直接用字符型,会一次性输出八位。
3、接收时,要注意先等起始位。
参考博客:
1、@Crazzy_M—— 什么是波特率,波特率怎么计算
2、 @丁林夕 —— 波特率与晶振
3、 @HopesunIce—— 使用单片机普通 IO 口模拟串口的三种方法

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moqim Flourite.

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值