STM8 普通IO配置模拟串口输出

2020-03-23来源: eefocus关键字:STM8  普通IO配置  模拟串口输出

刚接到上级的需求,由于stm8的串口资源较少,需要在原来工程的基础上加多一个io来输出串口数据。串口在每个学习单片机的人来说都是耳熟能详的东西。没有串口基础的同学建议先去学习串口知识点再来阅读。


首先我们知道串口数据配置里面包含:波特率、流控、数据起始位、数据位、奇偶校验位、停止位。针对本人经常选的配置为:

image.png

数据起始位默认都是1。数据实体如下:

由于本人选用波特率为115200 bps ,通过计算器算出每发送一位需要8.68us。这是一个非常低延时的值,这时候就要考虑写一个高精度的短延时的函数。那么问题来了,现在每次一个语句都是以微秒为单位的,任何写多一个语句和写少一个语句都会影响到这个延时函数,计算起来相当复杂。(去年自己写过高精度延时函数,但是是针对stm8在时钟频率是2mhz,且函数参数单位是1.5us的,但是最小延时只能是21us,无法把延时降到8.68us左右当时写出这个延时函数花费1-2天的时间去测试和验证,测试起来比较繁琐和麻烦)


为了更快更有效的完成这个需求,本人采取扫描方式来找到自己想要的延时时间。前提要先写好io模拟串口驱动,本人在stm8平台上对PD3做串口输出。


普通io模拟串口驱动分别写在了一个c文件和h文件中:


.C:


#include "analog_uart.h"

 

uint16_t ANALOG_TICK_N = 1;// 115200bps:18 ,9600bps:270

 

void analog_uart_init(void) {    //初始化

    GPIO_Init(TXD_PORT, TXD_PIN,GPIO_MODE_OUT_PP_HIGH_FAST);

}

 

inline void bxxx_delay(void) {   //延时值作为波特率需要的延时时间函数

    for(uint16_t i = 0; i < ANALOG_TICK_N ; ++i) {

        asm("nop");

    }

}

 

static inline void TXD_Write(uint8_t i) { //io 输出高或低电平

    if(i == 0) {

        TXD_PORT->ODR &= (uint8_t)(~TXD_PIN);

    } else {

        TXD_PORT->ODR |= (uint8_t)TXD_PIN;

    }

}

 

static void sent_byte(uint8_t byte) { // 模拟串口输出1个字节

    uint8_t i = 8;

    TXD_Write(0);

    bxxx_delay();

    while(i--) {

        TXD_Write((uint8_t)(byte&0x01));

        bxxx_delay();

        byte = byte >> 1;

    }

    TXD_Write(1);

    bxxx_delay();

 

void analog_uart_sent_data(uint8_t * data,uint16_t size) { // 模拟串口输出字符串

    uint16_t i = size;

    while(i--) {

        sent_byte(*data);

        ++data;

        bxxx_delay();

    }

}

 

void print_tick_num(void) {  //打印延时值出来,通过应用端对延时值做递增,在串口助手查找延时值

    uint8_t buf[10] = "N:";

    uitoa(ANALOG_TICK_N,(char *)buf+2);

    analog_uart_sent_data(buf,strlen((char *)buf));

}

 

/***

 * Description : 将无符号整数转为字符串.

 * Arguments   : val     待转换的整数.

 *               str     转换后字符串储存的数组指针.

 * Returns     : 返回转换后的指针.

 * Caller      : Application.

 * Notes       : None.

 *******************************************************************************

 */

static char* uitoa(uint32_t val, char *str)

{

    uint32_t power,j;

    char *p = NULL;

    if (str != NULL)

    {

        p = str;

        j = val;

        for (power = 1; j >= 10; j /= 10)

        {

            power *= 10;

        }

        for (; power > 0; power /= 10)

        {

            *p++ = '0' + val / power;

            val %= power;

        }

        *p = '';

        p = str;

    }

    return p;

}

.H:


#ifndef ANALOG_UART_H

#define ANALOG_UART_H

#include "stm8s.h"

#include

 

#define TXD_PORT  GPIOD

#define TXD_PIN   GPIO_PIN_3

 

extern uint16_t ANALOG_TICK_N ;


void analog_uart_init(void); // 初始化

void bxxx_delay(void);

static void sent_byte(uint8_t byte) ;

void analog_uart_sent_data(uint8_t * data,uint16_t size);  //发送串口数据

static char* uitoa(uint32_t val, char *str);

void print_tick_num(void) ;    // 查看延时时间数

 

#endif

在主函数完成相关操作


#include .....

#include "analog_uart.h"

 

..

 

 

void main(void) {

    /*相关初始化*/

    .....

    analog_uart_init();

    .....

    while(1) {

        print_tick_num();

        analog_uart_sent_data("fangrn",6);

        delay_ms(10);

        ANALOG_TICK_N ++;

    }

 

}


测试结果如下图:

发现,当N等于16或17时,数据是比较稳定,而N等于18的时候数据已经有部分丢失。此时stm8选择LSI内部时钟16Mhz的,当时测试的时候用的是LSI内部时钟4Mhz,结果没找到自己想要的延时。于是选择使用16MhzLSI,就找到延时值为16或17是存在于115200bps中。随着n不断增加,波特率就越低,最后会到一个无法打印出数据的时候。证明已经找不到自己想要的延时时间了。其实这种情况是不容乐观,因为LSI时钟其实并不稳定,单独测试的没问题,把它注入到较大的应用程序常常会部分乱码,因此建议降低波特率做开发,本人最后选择降低到9600bps进行扫描,9600bps算出来约104us。接下来对9600进行扫描


[2019-08-28_21:19:57:972] .:253&angj)aze

[2019-08-28_21:19:58:088] .:254&angj)aze

[2019-08-28_21:19:58:212] .:255fang猧aze? N:25秄ang猧aze? N:257fang?iaze

[2019-08-28_21:19:58:570] N:25竑angjiaze

[2019-08-28_21:19:58:691] N:259fangjiaz?

[2019-08-28_21:19:58:810] N:260fangjiaze

[2019-08-28_21:19:58:931] N:261fangjiaze

[2019-08-28_21:19:59:050] N:262fangjiaze

[2019-08-28_21:19:59:173] N:263fangjiaze

[2019-08-28_21:19:59:294] N:264fangjiaze

[2019-08-28_21:19:59:415] N:265fangjiaze

[2019-08-28_21:19:59:534] N:266fangjiaze

[2019-08-28_21:19:59:655] N:267fangjiaze

[2019-08-28_21:19:59:776] N:268fangjiaze

[2019-08-28_21:19:59:899] N:269fangjiaze

[2019-08-28_21:20:00:019] N:270fangjiaze

[2019-08-28_21:20:00:140] N:271fangjiaze

[2019-08-28_21:20:00:262] N:272fangjiaze

[2019-08-28_21:20:00:384] N:273fangjiaze

[2019-08-28_21:20:00:503] N:274fangjiaze

[2019-08-28_21:20:00:625] N:275fangjiaze

[2019-08-28_21:20:00:747] N:276fangjiaze

[2019-08-28_21:20:00:871] N:277fangjiaze

[2019-08-28_21:20:00:993] N:278fangjiaze

[2019-08-28_21:20:01:114] N:279fangjiaze

[2019-08-28_21:20:01:237] N:280fangjiaze

[2019-08-28_21:20:01:359] N:281fangjiaze

[2019-08-28_21:20:01:480] N:282fangj?aze

[2019-08-28_21:20:01:603] ?:283f?n?jiaz?

[2019-08-28_21:20:01:726] ?z284f??鏹i狷e

当扫描到257时,数据逐渐稳定,此时是比较乐观的,可以看到不少数据是稳定正确,这个时候选择中间值就是最稳定的。因此本人选择270这个值来延时作为串口波特率9600输出数据,这样加入到应用程序中就比较稳定了。

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

上一篇:STM8 I口模拟串口通信
下一篇:分析解决“STM8L101单片机IO口模拟串口通讯发生的奇怪现象”

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

推荐阅读

stm8l低功耗系列
最近干刚做了一个stm8的项目用的是L低功耗系列,其中遇到一个问题。外设寄存器的值怎么都写入不进去。用IAR仿真产看寄存器的值,不论写进去多少,都是初始值。后来把所有寄存器都写了一遍,发现有的能写进去,有的写不进去。比如GPIO的寄存器就能写进去。百思不得姐,偶然查看clock的库函数发现个函数是设置外设时钟的。这个系列,亦或者整个低功耗系列的每个外设是不是都需要在时钟寄存器中单独设置时钟。(以前所使用的芯片都是在外设寄存器中使能或者是禁使能)
发表于 2020-03-09
STM8L+BC26双低功耗,微安
现在在做一个项目需要用到STM8L和BC26。长时间断链后连接下服务器,并且发送一下当前状态,需要用到STM8L和BC26的低功耗。STM8L低功耗,这里用HALT模式,RTC规定时间唤醒。第一步需要关闭所有外设,把所有管脚为设置为输出,并且输出低,管脚根据具体环境设置,需要输出高电平的则输出高电平。在关闭外设的是后是需要先_DeInit,然后在关闭外设始终,有点需要特别主要,要把在进入halt模式的时候需要把所有的中断的标志位清空,否则使用RTC唤醒则会不起作用。第二步就设置低功耗的一些配置。第三步配置完成后进入低功耗。项目中需要用到外部高速始终和BC26通信,所以在进入和退出halt模式的时候需要重新初始化active模式下的
发表于 2020-03-09
stm8l151低功耗程序架构,调试心得
最近帮医院做了一款体温记录仪,整个硬件方案资源是:stm8L151 + NTC*2 + EEPROM + 锂电池充电保护电路 + 18mAh纽扣电池;软件逻辑是,每隔一分钟,采样两路温度并保存在EEP里;通过USB转TTL,上位机能够读取,展示温度曲线,最大最小平均值等简单的运算;整个方案很简单,但也走了不少弯路......单片机程序框架之伪代码:void main(void){    CLK_Config();    GPIO_Config();    ADC_Config();    USART_Config();   
发表于 2020-03-09
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之时钟设置
stm8 16M晶振下精确软件延时
void inerDelay_us(unsigned char n) {for(;n>0;n--) { asm("nop"); //在STM8里面,16M晶振,_nop_() 延时了 333nsasm("nop"); asm("nop"); asm("nop"); }}//---- 毫秒级延时程序----------------------- void Delayms(unsigned int time) { unsigned int i; 
发表于 2020-03-08
何立民专栏 单片机及嵌入式宝典

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

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