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  外部时钟  串口数据  传输错误 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic487475.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

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

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM8s外部时钟晶振失效时钟安全系统CSS启动演示
使用的最小系统晶振是8m的。这里说下配置过程:时钟自动切换,开启切换中断在中断里面清除中断标志,使能CSS并开启CSS中断CSS中断发生,清除CSS中断标志,将HSI二分频,即16M/2=8M,与外部晶振相同,这样不会影响串口波特率窗口输出配置信息:用手触碰PA1、PA2引脚使外部晶振失效串口输出CSS中断
发表于 2020-03-09
STM8s外部时钟晶振失效时钟安全系统CSS启动演示
STM8S103之时钟设置
最大时钟(指的是system clock):外部晶振24MHz,内部高速RC16MHz三个时钟源:外部晶振、内部高速RC(上电默认) +内部低速RC几个时钟:master clock(即sytem clock),fcpu,外设时钟、AWU时钟调用库函数中CLK_ClockSwitchConfig,参考库函数clk_clockselection,但是分频还得进一步设置上电默认:内部高速RC,HSIDIV=/8,CPUDIV=/1,外部时钟全使能,查看相关寄存器的Reset value
发表于 2020-03-09
STM8S103之时钟设置
STM8S如何跑24M的HSE晶振
就这么几步,第一步: 检查STM8s.h头文件配置/**  * @brief  In the following line adjust the value of External High Speed oscillator (HSE)   used in your application   Tip: To avoid modifying this file each time you need to use different HSE, you        can define the HSE value in your
发表于 2020-03-08
STM8S开发入门之使用EWSTM8(IAR STM8S)新建工程点亮一个LED
1、预先安装好EWSTM8(IAR STM8)软件,全称为IAR Embedded Workbench for STMicroelectronics STM8 IDE2、下载好STM8S标准库,此处所用标准库为STM8S_StdPeriph_Lib V2.3.13、新建个文件夹(名称自定),作为项目所在文件夹,并在项目文件夹里再新建两个文件夹,此处分别命名为FWLIB和USER。(注:这两个文件夹名字可以按你们自己意思取,无限制,如可以取HWLIB、SYSLIB、MYLIB、MYAPP、MYABC、XZY等)4、将STM8S标准库(STM8S_StdPeriph_Lib V2.3.1)——Project
发表于 2020-03-08
STM8S开发入门之使用EWSTM8(IAR STM8S)新建工程点亮一个LED
STM8L052定时器1配置30S
@[TOC]STM8L TIM1相关配置Tim1基本介绍TIM1由一个由可编程预分频器驱动的16位上下自动重载计数器组成。定时器可用于多种用途,包括:•时基生成•测量输入信号的脉冲长度(输入捕获)•生成输出波形(输出比较,PWM和单脉冲模式)•各种事件的中断功能(捕获,比较,溢出,中断,触发)•捕获,比较,溢出事件的DMA请求功能•与其他定时器或外部信号同步(外部时钟,复位,触发可校准)。该定时器非常适用于各种控制应用,包括那些需要具有互补输出和死区时间插入的中心对齐PWM功能的应用。定时器时钟可以来自内部时钟,也可以来自可通过配置寄存器选择的外部源。配置以下代码 自己配置了一个30S定时器,使用系统内部高速时钟16M,1600
发表于 2020-03-06
STM8S触摸按键固件库详解
由于刚好有小项目需要用到触摸按键,stm8s可以节约一块触摸按键的片子,并且成本比较低。在某些对成本比较敏感的应用还是有价值的。现将自己网上找到的资料与自己学习的心得记下与大家分析。ST的底层库对滚动条也支持,效果还是不错的一、原理分析ST的电容式触摸按键方案通过一个电阻和感应电极的电容CX构成的阻容(RC)网络的充电/放电时间来检测人体触摸所带来的电容变化。如上图所示,当人手按下时相当于感应电极上并联了一个电容Cx,增加了感应电极上的电容,感应电极进行充放电的时间会增加,从而检测到按键的状态。先用开关将 Cs(或 Cs+Cx)上的电放尽,然后断开开关,让 R 给 Cs(或 Cs+Cx)充电,当没有手指触摸的时候, Cs 的充电
发表于 2020-03-05
STM8S触摸按键固件库详解
小广播
何立民专栏 单片机及嵌入式宝典

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

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