STM8S使用外部时钟引起串口数据传输错误

发布者:数字梦想最新更新时间:2020-02-07 来源: eefocus关键字:STM8S  外部时钟  串口数据  传输错误 手机看文章 扫描二维码
随时随地手机看文章

最近有个小东西用到STM8S来驱动,之前用STM8S使用的是内部自带的16MHz RC时钟,尚未尝试过使用外部晶振作为主时钟。今天记录一下使用外部晶振时遇到的一个问题。


老规矩,在进行程序设计时,首先初始化时钟,本次使用的是STM8S103F3P6芯片,8MHz的外部晶振,为了方便内外部时钟切换,结合资料写了两个切换函数

/***********************************************

*描述:采用内部16MHz的RC时钟为主时钟

*      初始化时钟为1分频 16M,无外部晶振

*版本:V1.0

*作者:

************************************************/

void HsiInit(void)

{

    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);

}

/***********************************************

*描述:采用8M外部晶振为主时钟,用于时钟切换    

*版本:V1.0

*作者:

************************************************/

void HseInit(void)

{   

  CLK_DeInit();                                         //时钟初始化

  CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);              //8MHz,不分频

  CLK_HSECmd(ENABLE);                                   //外部时钟开  

  CLK_HSICmd(ENABLE);                                   //内部RC开 

  while(SET != CLK_GetFlagStatus(CLK_FLAG_HSERDY));    //等待外部晶振起振 

  CLK_ClockSwitchConfig(CLK_SWITCHMODE_MANUAL,CLK_SOURCE_HSE,DISABLE,CLK_CURRENTCLOCKSTATE_DISABLE);

  CLK_ClockSwitchCmd(ENABLE);                           //开始切换 

}

在主函数调用所需的时钟函数即可,为了验证外部时钟是否切换成功,我在定时器1的通道1输出PWM进行验证,所幸得到了想要的波形,定时器1的配置如下


/***********************************************

*描述:TIM1CH1(PC6)输出PWM,频率为1K

*      定时器时钟为外部的8MHz

*版本:V1.0

*作者:

************************************************/

void TIM1_Init(void)

{

    TIM1->EGR = 0x01;//重新初始化定时器1

    TIM1->CR1 = 0x00;//边沿对齐方式,向上计数,发生更新事件,计数器不停止更新

    TIM1->RCR = 0x00;//重复计数器的值为0,计时时间到,重复多少次产生中断,该值是重复多少次那个值

    

    //设定预分频为,80分频 8M

    TIM1->PSCRH =0x00;  //PWM的时钟 影响周期

    TIM1->PSCRL =0x4f;  //80分频,TIM1的时钟为100K

 

    TIM1->ARRH = 0x00;  //设定重装载值

    TIM1->ARRL = 0x63;  //计数100次,等于T,即1ms(f=1K),每10us计一个数

 

    //CH1

    TIM1->CCER1 = 0x01; //CC2ER1开启CH1,CC1配置入输出,低电平有效

    TIM1->CCMR1 = 0x68; //PWM模式1,使能预装载

 

    //设置占空比

    TIM1->CCR1H = 0x00;

    TIM1->CCR1L = 0x0A;  // 占空比值

 

    TIM1->OISR &= ~0x03;

    TIM1->BKR |= 0x80;   //刹车

    TIM1->CR1 |= 0x01;  //使能TIM1计数器

    

//    GPIO_Init(GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST);

    GPIOC->DDR|=0xff;//输出

    GPIOC->CR1|=0xff;//推挽

    GPIOC->CR2|=0xf0;//速度

}


接下来开始进入本次主题,采用8MHz外部时钟时,串口1传输数据异常。开始时串口初始化函数如下,使用波特率是9600


void Uart1_Init(u32 Baudrate)

{

    UART1_DeInit(); 

    UART1_Init((u32)Baudrate, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);

    UART1_Cmd(ENABLE );  //启用串口

}


如果使用的是内部的16MHz时钟,这三行初始化代码应该可以启动串口传输数据,但是我发现数据在传输的过程中出错,刚开始也怀疑是串口配置出错,假如配置出错,理论上是不会收到数据的,上面的代码能在内部时钟下正常传输数据,在外部时钟下传输出错,那很大可能就是波特率出现了问题。


串口初始化的波特率是9600,串口调试助手在9600的波特率下得不到正确的数据,printf打印出来的是乱码


啒f槝骧槝灅?榾ff啒f槝骧槝灅?榾ff啒f槝骧

槝灅?榾ff啒f槝骧槝灅?榾ff啒f槝骧槝灅?榾ff

啒f槝骧槝灅?榾ff啒f槝骧槝灅?榾ff啒f槝骧

槝灅?榾ff啒f槝骧槝灅?榾ff啒f槝骧槝灅?榾ff

啒f槝骧槝灅?榾ff啒f槝骧槝灅?榾ff啒f槝骧

槝灅?榾ff啒f槝骧槝灅?榾ff啒f槝骧槝灅?榾ff

当我把串口调试助手的波特率改为4800后,神奇的一幕出现了


ART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!

UART1 is OK!


为什么呢?很好奇发生了什么,我把波特率两个寄存器值打印出来


UART1->BRR2: 2

UART1->BRR1: 68

UART1->BRR2: 2

UART1->BRR1: 68

UART1->BRR2: 2

UART1->BRR1: 68

UART1->BRR2: 2

UART1->BRR1: 68


结合STM8S参考手册,将这两个寄存器的值还原,得到UART_DIV = 0x0682,十进制就是UART_DIV = 1666,按照公式:


UART_DIV  = F / Baudrate,其中F是主时钟频率,Baudrate是波特率,为9600


那么主时钟频率 = 1666 * 9600 = 15993600,接近16MHz,通过上面可以观察到,UART_DIV = 1666对应的是16MHz,那么8MHz应该为多少?


UART_DIV  =  8000 000 / 9600 = 833.3,即UART_DIV  = 0x0341


参考数据手册的设置规则,BRR1和BRR2的值应该为

UART1->BRR2 = 0x01;

UART1->BRR1 = 0x34;


所以串口初始化函数应该为(注意必须是先设置BRR2,再设置BRR1)


void Uart1_Init(u32 Baudrate)

{

    UART1_DeInit(); 

    UART1_Init((u32)Baudrate, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);

    UART1->BRR2 = 0x01;

    UART1->BRR1 = 0x34;

    UART1_Cmd(ENABLE );  //启用串口

}

此时,再将串口调试助手的波特率设置为9600,可以得到如下数据


UART1->BRR2: 1

UART1->BRR1: 34

UART1->BRR2: 1

UART1->BRR1: 34

UART1->BRR2: 1

UART1->BRR1: 34

UART1->BRR2: 1

UART1->BRR1: 34

UART1->BRR2: 1

UART1->BRR1: 34

UART1->BRR2: 1

UART1->BRR1: 34

UART1->BRR2: 1

UART1->BRR1: 34


至此,串口调试完成,引起传输数据出错,应该是库函数计算波特率是以内部的16MHz频率作为标准,假如你要用到其他频率,需要重新设置BRR1和BRR2这两个寄存器的值。

关键字:STM8S  外部时钟  串口数据  传输错误 引用地址:STM8S使用外部时钟引起串口数据传输错误

上一篇:STM8S的按键PWM调光灯历程
下一篇:使用STM8S003K3 ADC简介以及初始化

推荐阅读最新更新时间:2024-10-28 09:26

stm8s跳出中断程序c语言,STM8S I2C总线中断程序
/*========================================================================================================== 本源程序文件内部使用的一些操作指令的宏定义 ==========================================================================================================*/ /*-----------------------------------------------------------------------------
[单片机]
串口通信实验程序(数据接收)
试验效果如下: #include reg51.h #define duan P0 //段选 #define wei P2 //位选 unsigned char code wei1 = { 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//位选控制 查表的方法控制 unsigned char code duan1 = { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码 unsigned char
[单片机]
<font color='red'>串口</font>通信实验程序(<font color='red'>数据</font>接收)
stvd+stm8s: ERROR:before starting debug session, please, select a target
STVD在仿真调试stm8s时报错如下错误: 问题原因:STVD没有设置调试用仿真器 解决方法:点击STVD菜单栏选择 Debug instrument - Target Settings... ,选择“Swim ST-Link” 进行上述设置后,仍然报如下错误: 问题原因:安装ST TOOLSET 的时候,DAO-3.5 的文件并没有被正确安装。 解决方法:进入ST TOOLSET 的安装文件夹,比如D:Program Files(x86)STMicroelectronicsst_toolsetstvddao。 运行在此文件夹下的ST Toolset.msi,先卸载已安装的,再重新安装即可解决问题。
[单片机]
stvd+stm8s: ERROR:before starting debug session, please, select a target
STM32与上位机串口通讯的学习笔记(简明的数据帧设计方法)
最近因为项目需要,需要做一个STM32和Windows的串口通讯协议来交换数据,本着追求极致的心态,来讨论一下简明的数据帧的设计方法。 ##数据的传输方式 对于很多单片机初学者而言,可能他们接触到串口 首先想到的就是通过串口打印字符串,然后就会很理所当然的想到了用“打印”的方式来传输数据。 比如我们需要传输一个float型的数据value,可能小白们首先会想到的方式就是串口重定向printf然后像下面这样把数据传输过去 printf( %f ,&value); 但是实际上,对于程序之间的交流,使用字符串打印这样的方式是非常浪费传输数据的,因为假设这个浮点数据为1234.567占了8个字符(小数点也占一位) 所以用字
[单片机]
把每一分钱都花在刀刃上,MCU性能需物尽其用
对于开发人员来说,选择一款合适的MCU,在如今品牌繁多的MCU市场上变得日趋复杂。Siliconlabs推出了0.9V工作电压的8位MCU,TI则拥有低功耗的MSP430系列。Infineon和Freescale除了有汽车MCU外还有广泛的非汽车用MCU产品。Atmel的AVR,Microchip的PIC家族等等都为这个市场提供了更多的选择性。除此之外,还有基于ARM Cortex-M3的32位MCU不断发布,而8051架构仍然在继续风靡。 在位数、内核的区分已经日益模糊的现在,MCU将如何发展?或许从设计人员的角度来看,低功耗,高集成度将成为一种普遍的趋势,同时,充分利用MCU的每一位性能,做到毫无浪费,在经济成本
[单片机]
STM8S单脉冲方式和重复计数器
STM8S的单脉冲方式在检测过零点信号触发可控硅导通的应用中比较适合。先了解下可控硅的导通条件。 可控硅导通需要满足两个条件: 1、 可控硅阳极和阴极间必须加正向电压 2、 控制极也要加正向电压 以上两个条件必须同时具备,可控硅才会处于导通状态,另外,可控硅一旦导通后,即使降低控制极电压或去掉控制极电压,可控硅仍然导通。 可控硅关断条件:降低或去掉加在可控硅阳极至阴极之间的正向电压,使阳极电流小于最小维持电流以下。 通过改变可控硅控制角可调节可控硅整流输出电压。 配置TIM1_CH1为输入通道,接50HZ交流过零检测信号。TIM1_CH2为输出通道,控制可控硅导通。 PWM初始化代码如下: STM8S
[单片机]
<font color='red'>STM8S</font>单脉冲方式和重复计数器
HAL库教程5:串口数据发送
使用CubeMX配置串口1 配置引脚   我的板子上使用插针引出了串口1,串口1连接PA8与PA9。 配置串口通信参数   使能串口1,并配置为同步模式,波特率为115200,模式8N1。 使能串口中断 查看生成的代码   引脚与中断的初始化在stm32f4xx_hal_msp.c   而通信用到的参数,如波特率校验方式等初始化在main.c。   同样是串口初始化的代码,为什么要分开写?   可能是分层思想,换板子的话,只用修改引脚与中断的函数,用户函数不用修改。比如用户关心波特率,不用关心引脚。 按键控制串口发送代码编写   通过串口打印按键的信息。 //main.c int main(vo
[单片机]
HAL库教程5:<font color='red'>串口</font><font color='red'>数据</font>发送
ATmega168 外部时钟
ATmega168可用外部时钟源驱动,如Figure 15所示的进行连接。 此时CKSEL熔丝位必须按照Table15编程。 选择了这个振荡源之后,启动时间由熔丝位 SUT确定,如 Table16 所示。 为了保证MCU 能够稳定工作,不能突然改变外部时钟源的振荡频率。工作频率突变超过2% 将会产生异常现象。应该在MCU 保持复位状态时改变外部时钟的振荡频率。 要注意的是,系统时钟预分频可以实现在运行期间改变内部时钟频率而保持系统稳定运 行。请参见 P31”系统时钟预分频器 ” 。
[单片机]
ATmega168 <font color='red'>外部</font><font color='red'>时钟</font>
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved