SDCC编译STC15虚拟串口输出打印示例程序

SDCC编译STC15虚拟串口输出打印示例程序

前言

STC15W408AS(51系列) 单片机从 Keil 迁移到 SDCC上进行开发时,直接使用 Keil上使用的 Soft_UART.c 中的软件模拟串口,通信出现错误,但是同样的代码在 Keil 上编译后下载到单片机执行没有问题。

这也侧面说明了 SDCC和Keil之间编译时存在一些差异的。

原因定位

库的说明是模拟串口,9600波特率,其中延时函数如下所示,其中MAIN_Fosc 是MCU的时钟频率。

void	BitTime(void)
{
	u16 i;
	i = ((MAIN_Fosc / 100) * 104) / 130000L - 1;		//根据主时钟来计算位时间
	while(--i);
}

这里移植后串口通信错误,是这个BitTime 延时不对无误了,因为其他部分肯定没有问题,在Keil上执行的好好的。

我的工程配置的主时钟为33MHz 。

[env:STC15W408AS]
platform = intel_mcs51
board = STC15W408AS
board_build.f_cpu = 33000000L ; 设置时钟频率 5.5296MHz, 6M, 11.0592M, 12M, 18.432M, 20M, 22.1184M, 24M, 27M , 30M, 33M, 33.1776M 

; build_flags =  
;     --model-small

[platformio]
    src_dir = ./ 
    ; include_dir = ./

在这里插入图片描述

9600波特率换算为时间为:
Δ t = 1 s 9600 = 1000000 9600 = 104.167 u s \varDelta t=\frac{1s}{9600}=\frac{1000000}{9600}=104.167us Δt=96001s=96001000000=104.167us

于是我们知道 i = ((MAIN_Fosc / 100) * 104) / 130000L - 1; 这个是用来延时 104us的,在 delay.c中给出了ms级别延时的函数如下所示:

void  delay_ms(unsigned int ms)
{
	unsigned int i;
	do{
		 i = MAIN_Fosc / 13000;
		while(--i)	;   //14T per loop
	}while(--ms);
}

所以实际上i = ((MAIN_Fosc / 100) * 104) / 130000L - 1; 应该是 i = (MAIN_Fosc / 13000000L)*104 - 1; ,就是延时104us ,大概是考虑到一一般时钟频率最后两位都为0,以及防止溢出进行了变形处理。

这么看来串口通信错误实际上就是延时出错了,我们只需要就纠正这个延时函数中的 13000 ,就可以推出正确的公示了。

首先看一下再没有纠正之前实际的延时时间:

测试的代码如下所示,理论上高低昂坪时间会持续1s,通过测试,发现高电平的时间为 921.745ms,比预期的小了,说明延时中除数为 13000 大了。

void  main()
{
	while(1)
	{
		//循环交替让红灯、蓝灯闪烁
		Led_Red = 1;
		P1_2 = 1;
		delay_ms(1000);
		Led_Red = 0;
		P1_2=0;
		delay_ms(500);
	}
}

在这里插入图片描述

修正延时公式,原来的延时公式为

void  delay_ms(unsigned int ms)
{
	unsigned int i;
	do{
		 i = MAIN_Fosc / 13000;
		while(--i)	;   //14T per loop
	}while(--ms);
}

现在除数值修正为 13000 * 0.921591 = 11980.683 ,考虑到此处时钟频率较高,我们可以微调一下改制,让其适配多个时钟频率,不妨取12000试一试 。

改为

void  delay_ms(unsigned int ms)
{
	unsigned int i;
	do{
		 i = MAIN_Fosc / 12000;
		while(--i)	;   //14T per loop
	}while(--ms);
}

此时高电平持续时间为998.360333ms,误差很小,不影响9600波特率的串口!

在这里插入图片描述

代码修改

根据前面的定位分析,修改延时代码如下:

void  delay_ms(unsigned int ms)
{
	unsigned int i;
	do{
#ifdef __SDCC 
		i = MAIN_Fosc / 12000 ; // 12018;
#else 
		 i = MAIN_Fosc / 13000;
#endif 
		while(--i)	;   //14T per loop
	}while(--ms);
}

串口中的延时代码更改为:

void	BitTime(void)
{
	u16 i;
#ifdef __SDCC
	i = ((MAIN_Fosc / 100) * 104) / 120000L - 1;
#else 
	i = ((MAIN_Fosc / 100) * 104) / 130000L - 1;		//根据主时钟来计算位时间
#endif 
	while(--i);
}

测试工程的主函数代码为:

void  main()
{
	while(1)
	{
		//循环交替让红灯、蓝灯闪烁
		Led_Red = 1;
		P1_2 = 1;
		delay_ms(1000);
		Led_Red = 0;
		P1_2=0;
		delay_ms(500);
		// TxSend('0');
		PrintString("Hello World!\r\n");
	}
}

串口接收的数据结果如下所示:

在这里插入图片描述

工程源码链接

pio-stc15w408-uart

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值