我是靠谱客的博主 清爽指甲油,最近开发中收集的这篇文章主要介绍6 8051使用Keil模拟器和调试输出窗口实现串口收发回环,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

  • 本仓库相关网址:
    CSDN文章地址
    Gitee工程和源码地址

  • 相关仓库:
    嵌入式整体介绍,里面也描述了部分8051的内容:
    才鲸嵌入式 / 嵌入式知识图谱WiKi
    C语言框架讲解,让你对C语言要学哪些东西有一个完整的了解:
    embedded_programming_skills/ 0_doc / 02-C语言框架讲解.md

6)Keil调试输出窗口串口回环

  • 本工程主要演示使用Keil创建一个默认工程,然后添加串口0的回环收发用例,在Keil的调试串口进行串口收发,并且可以使用虚拟串口,通过SSOM32与Keil通信来进行串口收发。

  • 工程文件:本文档同级目录/06_uart0_loopback/06_uart0_loopback.uvproj

  • 将Keil的UART #1调试输出串口与SSCOM32等串口软件绑定的话,需要用到VSPD软件。

  • 参考网址:

    • Keil实例仿真AT89C51串口UART收发数据(附程序)
    • keil MDK 中使用虚拟串口调试串口
    • 虚拟串口 VSPD 的使用
  • 代码展示:

/*******************************************************************************
 * brief	进行串口0的回环输入输出
 * details	可以通过Keil的UART #1调试串口直接输出串口信息和接收串口的输入,
 *			也可以通过VSPD虚拟串口软件与PC上的SSCOM32等串口软件进行绑定,通过
 *			串口软件收发信息。
 * attention	Keil UART #1和SSCOM32窗口输入的行尾是r,不是rn,
 *				但是输出又是以rn来处理的。Keil模拟器模式下,
 *				晶振不管设置为多少,UART0不管是否初始化,设置多少波特率,Keil
 *				UART #1调试串口的收发总是115200的波特率。
 * author	将狼才鲸
 * date	2022-10-30
 * note	参考网址:
 *			[Keil实例仿真AT89C51串口UART收发数据(附程序)]
 *			(https://blog.csdn.net/tj_nonstoper/article/details/124271543)
 *			[keil MDK 中使用虚拟串口调试串口]
 *			(https://blog.csdn.net/NICHUN12345/article/details/124423615)
 *			[虚拟串口 VSPD 的使用]
 *			(https://blog.csdn.net/qq_17351161/article/details/89607458)
 ******************************************************************************/

/********************************** 头文件 ************************************/
#include <reg51.h>	/* 8051通用的寄存器定义 */

/********************************** 宏定义 ************************************/
#define CHAR_LOOPBACK		/* 收到一个字符就返回一个字符 */
//#define STRING_LOOPBACK	/* 收到一行后再返回一行,如果接收buffer满则先返回整个buffer数据 */
/* Keil使用自带的模拟器运行时,输入的换行是r,但输出换行却是rn */
#define FIX_KEIL_EMULATOR_AND_SSCOM32_UART_LINE_FEED_ISSUE

#define BUF_MAX_SIZE 16		/* 设置短一点,即使没输入正确的换行符,也能及时有数据返回 */

/********************************* 全局变量 ***********************************/
static char rcv_buf[BUF_MAX_SIZE] = {0};	/* 完整的一行接收缓存 */
static int rcv_cnt = 0;	/* 接收的字节数 */
static char rcv_str_end_flag = 0; /* 0 is false, !0 is true */

static void uart0_init(void);
static void send_str(char *str);
static void send_char(char c);

//如果要使用printf,需要进行putchar输出重定义
//不使用printf,直接往串口写数据也能输出到UART #1
///**
// * brief		printf重定向的函数,这里重定向到串口0
// * param[in]	c	承接printf中传入的一个字符
// * note		这里的函数注释格式是Doxygen,有兴趣的可以自行去了解
// * return		正常时返回c,错误时返回错误码
// */
//char putchar(char c)
//{
//	ES = 0;				/* 关串口中断 */
//	SBUF = c;           
//	while (TI != 1);	/* 等待发送成功,产生发送中断 */
//	TI = 0;				/* 清除发送中断标志 */
//	ES = 1;				/* 开串口中断 */

//	return c;
//}

/********************************* 接口函数 ***********************************/
/**
 * brief	入口函数
 */
int main()
{
	/* 1. 串口初始化 */
	uart0_init();
	
	/* 2. 打印提示信息 */
	send_str("====rn");
	send_str("| Check your terminal line end format.rn");
	send_str("| r \r r");
	send_str("| n \n n");
	send_str("| nr \n\r nr");
	send_str("| rn \r\n rn");
	send_str("====rnrn");

	send_str("====rn");
#ifdef STRING_LOOPBACK
	send_str("Now is string loopback modern");
	send_str("Please input string, and end with \r or \n.rn");
#else
	send_str("Now is char loopback modern");
	send_str("Please input charrn");
#endif

	/* 3. 打印从串口中断收到的信息 */
	while (1) {  	 
		if (rcv_str_end_flag) {
			/* 如果收到数据,则进行回环输出 */
			rcv_str_end_flag = 0;
#ifdef STRING_LOOPBACK
			send_str("Your Input: ");
			send_str(rcv_buf);  /* 把接收到的字符串发送回去 */
#else
			/* 防止有人不知道串口中断输入是没有回显的,原样输出会以为只是自己的输入 */
			send_char('>');
			send_char(rcv_buf[0]);
#	ifdef FIX_KEIL_EMULATOR_AND_SSCOM32_UART_LINE_FEED_ISSUE
			if (rcv_buf[0] == 'r')
				send_char('n');
#	endif
			send_char(' ');
#endif

			rcv_buf[0] = ''; /* 清空字符串,直接写个字符串结尾 */
		}
	}
}	

/********************************* 私有函数 ***********************************/
/**
 * brief		串口0初始化
 * attention	Keil模拟器模式时可以不初始化,即使配置了参数,也始终以115200波特率输出
 * note		不初始化的话能输出数据,但是进不了接收中断,接收不了信息
 */
static void uart0_init(void)
{
	/* 串口参数配置函数,这里配置为9600波特率,1位停止位,8位数据位,无校验 */
	TMOD = 0x20;  /* Timer1以定时模式工作在方式2:8位常数自动装入定时器/计数器 */
	SCON = 0x40;  /* SM0 = 0,SM1 = 1,方式1,10位UART "0 D0~D7 1",波特率可变 */
	REN  = 1;     /* 允许串口接收数据位 */
	/** warning 不管设置多少波特率,Keil模拟器在UART #1中的收发始终是115200 */
	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 */
}
 
/**
 * brief		发送一个字符
 * param[in]	c	发送的字符
 */
static void send_char(char c)
{
   SBUF = c;		/* SBUF是指串行口同地址的两个缓冲寄存器,一个是发送寄存器,一个是接收寄存器,通过读和写来区分 */       
   while (!TI);		/* 等待一个字符发送完毕 */
   TI = 0;			/* TI软件清零,等待下一次发送后的置位 */
}

/**
 * brief		发送一个字符串
 * param[in]	str	要发送的字符串指针
 */
static void send_str(char *str)
{
	ES = 0; /* 发送前关闭串口中断,以防发送完每个字符都没必要地进入中断程序 */

	while (*str != '')		/* 持续发送直到字符串结尾 */
		send_char(*str++);	/* 先取值再自增 */

	ES = 1; /* 发送完打开串口中断 */
}
 
/**
 * brief	串口0中断处理函数
 * note	中断默认优先级:0外部中断0 > 1定时/计数器0 > 2外部中断1 > 3定时/计数器1 > 4串行中断
 */
void uart0_irq(void) interrupt 4 
{
	if (RI == 1) {
		/* RI置位表示一帧数据接收完毕,中断处理后RI必须用软件清0 */
		RI = 0; /* 中断标志位清零 */
		ES = 0; /* 关闭串口中断,防止下面程序执行时被打断,防止中断嵌套 */
#ifdef STRING_LOOPBACK
		if (rcv_cnt < BUF_MAX_SIZE - 2) {
			/* 接收缓冲区未溢出 */
			rcv_buf[rcv_cnt] = SBUF; /* 存放1个字节 */
			if (rcv_buf[rcv_cnt] == 'r' || rcv_buf[rcv_cnt] == 'n') {
				/* 如果接收到结束符(当前Keil UART #1和SSCOM都是r) */
				rcv_str_end_flag = 1;	/* 接收了完整的字符串 */
#ifdef FIX_KEIL_EMULATOR_AND_SSCOM32_UART_LINE_FEED_ISSUE
				rcv_buf[rcv_cnt - 1] = 'n';
#endif
				rcv_buf[rcv_cnt] = '';	/* 在字符串末尾补字符串结束 */
				rcv_cnt = 0; /* 接收长度清0 */
			} else {
				rcv_cnt++;
			}
		} else {
			/* 接收缓冲区溢出 */
			rcv_str_end_flag = 1;
			rcv_buf[rcv_cnt] = '';
			rcv_cnt = 0;
		}
#else
		rcv_buf[0] = SBUF; /* 存放1个字节 */
		rcv_str_end_flag = 1;
#endif

		ES = 1;	/* 中断处理完重新打开串口中断 */
	}
}

最后

以上就是清爽指甲油为你收集整理的6 8051使用Keil模拟器和调试输出窗口实现串口收发回环的全部内容,希望文章能够帮你解决6 8051使用Keil模拟器和调试输出窗口实现串口收发回环所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部