历史上的今天
返回首页

历史上的今天

今天是:2025年02月24日(星期一)

正在发生

2020年02月24日 | STM8S003F使用I/O口模拟串口(一)发送数据

2020-02-24 来源:eefocus

最近在使用STM8S003F模拟串口发送数据,网上资源很多,但是没有找到我需要的,因此自己写一篇文章,做一个总结,这篇文章主要是不用库函数实现发送简单的过程。


1、串口通信原理和模拟串口发送数据的原理

标准串口数据格式为:起始位(1bit)+数据位(8bit)+校验位(1bit)+停止位(1bit)。其中起始位为低电平,停止位为高电平。


串口通讯需要设置波特率和检查COM口。


思路是这样的,我们使用定时器TIM2来定时,每隔一端时间发送一个位,从而实现模拟串口发送数据。


2、获得定时器ARR自动装载的值

为了简便,我们不要校验位,因此共有10个位的数据。


我以stm8中9600bit/s的波特率计算的过程为例(1秒钟传输9600位)。


可以计算出传输1位所需要的时间 T1 = 1/9600 约为104us。


stm8 内部晶振频率为16M,我采用16分频也就是1M,故MCU震荡周期为 1/1M = 1us。


由上面的计算我们可以知道要发送一位数据,定时器中定时的自动装载的值应设为为 104/1 =104。


3、实现过程

在实现过程中,我们在工程文件夹SimUART中共分了4个文件夹(分别为System:存放系统文件;Project:存放项目文件;User:存放main.c和UserApp.c;My_Lib:存放其它常用的文件)。根据我们将用到的单片机的资源,我们在My_Lib中分了三个文件,分别是——Delay:存放与延时函数相关的文件;IO:存放与IO口相关函数的文件;Time:与定时器相关函数的文件。下面我贴出相关函数的.c文件,而.h文件省略不写,有需要的同学可以根据文章后面的网址下载使用。我的编程环境是IAR,需要自己建立IAR工程。MARK,以后介绍。下面详细介绍(Project和System省略不写,其中System只用了stm8s.h)。


3.1、一切从main.c开始

首先,在main.c中我们需要对用到的单片机的资源进行初始化。我们将其写在All_Config()【在UserApp.c中】函数内,代码如下:


//head file 

#include "UserApp.h"

#include "IO.h"

#include "User.h"

#include "Time.h"

 

//初始化函数

void All_Config( void )

{

    Clock_Config();

    IO_Init();  

    TIM2_Init();

}



其中User.h是我将自己常用的宏写在了一个文件里面,对应于main.c。


在没有接外部时钟的时候,STM8S003F在启动时主时钟默认为HSI RC时钟的8分频,我们这里的初始化仅指定为16MHZ高速内部RC振荡器(HSI),也可以省略不写,Clock_Config()【在UserApp.c中】函数代码如下:

//初始化时钟 选择内部16M晶振

void Clock_Config()

{

    CLK->CKDIVR &= ~( BIT(4) | BIT(3) );

}



我选择单片机的PD2作为我的模拟串口的数据发送口,IO_Init()【在IO.c中】函数代码如下:




//head file

#include "IO.h"

#include "User.h"

 

void IO_Init()

{

    //TXD:TXD位推挽输出  PD2

    UART_PORT->ODR |= UART_PIN_TX; //0000 0000

    UART_PORT->DDR |= UART_PIN_TX; //0000 1000

    UART_PORT->CR1 |= UART_PIN_TX; //0000 1000  

    UART_PORT->ODR &= ~UART_PIN_TX;

    UART_PORT->ODR |= UART_PIN_TX;

}

其中在IO.h中的宏定义为:




#define UART_PORT GPIOD

#define UART_PIN_TX 0X04 //  PD2

#define UART_PIN_RX 0X08 //  PD3


下面是定时器的初始化,在使用定时器的时候我们分为以下几步:


a、选择定时器,我们选择TIM2;


b、定时器的时钟分频(注意要看是使用的默认8分频还是有更改),我开始没有分频,需要16分频;


c、填充定时器自动装载的值,我这里是104;


d、开启定时器;


注意计数器CNTR上电自动为0,我们还是清零一下,使用的自动装载寄存器后,自动重装载寄存器决定了定时器的上溢时机,当定时器的计数器中数值达到了自动重装载寄存器规定的值,计数器就要归零。也就是说自动重装载寄存器决定了定时器的周期。


在这篇文章介绍的模拟串口发送数据的方法中并没有使用中断。TIM2_Init()【在TIM2.c中】函数代码如下:


//head file

#include "TIM2.h"

#include "User.h"

 

void TIM2_Init()

{

    CLK->PCKENR1 |= CLK_PCKENR1_TIM2;   //TIM2 enable  

    TIM2->PSCR    = 0x04;               //16分频 1MHZ 1us

    TIM2->ARRH    = 104 >> 8;           //自动装载 每52us复位一次TIM2

    TIM2->ARRL    = 104;                //每1us递减1

    TIM2->CNTRH = 0;

    TIM2->CNTRL = 0; 

TIM2->CR1 |= TIM2_CR1_CEN; //开启定时器}

完成初始化以后,我们应该写发送程序,为了简单的发送,我们选择发送0x55,因为它在示波器中显示方波。我们在UserApp.c中写我们的实现我们的模拟串口的发送。

发送数据的规则是:


a、共10位数据(因此需要16为的数据,8位是不行的),由于我们发送的数据是8位,所以有一个转换的过程;


b、先发低位,再发高位;


c、在发送函数中有时间延时代码,保证没法每一次数据都是一个计数时间(即完成一次104计数)


发送函数SimUART_TxByte()【在UserApp.c中】代码如下


void SimUART_TxByte( u8 SendData )

{

    static u16 Send_All = 0;

    static u8  BitNum   = 0;                //位计数

    Send_All = SendData;

    Send_All = ( Send_All << 1 ) | 0X0200;  //需要发送的10个位的数据

    TIM2->CNTRH = 0;

    TIM2->CNTRL = 0;  

    TIM2->SR1 &= ~TIM2_SR1_UIF;

 

    //先发低位,再发高位

    for( BitNum = 0;  BitNum<10 ;  BitNum++ )

    {

        if( Send_All & 0X0001 )                 //如果是高电平,发高电平

        {

            UART_PORT->ODR |= UART_PIN_TX;

        }

        else                                    //如果是低电平,发低电平

        { 

            UART_PORT->ODR &= ~UART_PIN_TX;

        }

        Send_All >>= 1;                         //右移一位

        

        //等待波特率时间 

        while( (TIM2->SR1 & TIM2_SR1_UIF) == 0 );

        TIM2->SR1 &= ~TIM2_SR1_UIF;

    }

}

其中UART_PIN_TX为IO.c中的宏定义。


3.2、补全main()函数

完成上面的代码之后我们可以测试一下,下面我们完成main()函数,代码如下:


//head file 

#include "User.h"

#include "UserApp.h"

#include "Delay.h"

 

int main( void )

{

    char Test = 0;

    //char Test = 0x55;             //测试数据  

    All_Config();                   //初始化

 

    while(1)                        //发送循环

    {

        SimUART_TxByte( Test++ );

        Delay_50000();              //延时,防止数据过多

    }

    //return 0;

}


在0x55发送正确之后,我们发送0x00到0xFF,若波特率不正确将会出现发送不连贯的现象。为了防止数据过多,我们需要一个延迟函数,Delay_50000()【IO.C中】函数代码如下:

//Head file

#include "Delay.h"

 

void Delay_50000()

{

    int a,b;

    for( a=0 ; a<100 ; a++ )

    {

        for( b=0 ; b<500 ; b++ );

    }

}

4、结束语

至此我们使用IO口模拟串口(未使用库函数)发送数据的功能已经实现,相关代码可以移步下面的地址下载使用,欢迎大家和我一起学习和交流。

推荐阅读

史海拾趣

HP(Keysight)公司的发展小趣事

HP(Keysight)公司发展故事

故事一:初创时期的艰辛与突破

HP(惠普)的起源可以追溯到1939年,由威廉·惠普(William Hewlett)和戴维·欧文(David Packard)在美国加州的一个小车库内创立。最初,他们专注于生产音频振荡器,这是一种用于测试音频设备的设备。尽管条件简陋,但凭借过人的技术和敏锐的市场洞察力,他们的产品很快获得了市场的认可。这一成功为公司奠定了坚实的基础,也为后续进入电子仪器和计算机领域铺平了道路。

故事二:半导体技术的先驱

1940年,HP公司开发出了第一台采用半导体技术的电子计算机,这在当时是一项革命性的成就。这台计算机不仅能够执行复杂的计算任务,还标志着HP在半导体技术领域的领先地位。这一突破不仅为公司赢得了业界的尊重,也为后续的微型计算机和个人计算机的发展奠定了基础。

故事三:微型计算机市场的开拓者

1960年,HP公司再次引领行业潮流,开发出了世界上第一台商用微型计算机。这台计算机采用了更小的集成电路,比之前的计算机更加小巧、便宜且易于使用。这一创新不仅降低了计算机的门槛,使得更多人能够接触到计算机,也推动了计算机技术的普及和应用。HP在微型计算机市场的成功,进一步巩固了其在电子行业的领导地位。

故事四:个人电脑市场的崛起

进入70年代,HP公司开始涉足个人电脑市场。1970年,HP发布了第一台商业个人计算机(PC),这一举措标志着公司正式进入了一个全新的业务领域。随着个人电脑市场的迅速发展,HP不断推出新产品,满足消费者的多样化需求。从早期的台式机到后来的笔记本电脑,HP始终保持着技术领先优势,为用户带来更加便捷、高效的计算体验。

故事五:并购与多元化发展的战略

在发展过程中,HP公司也通过并购等方式不断拓展业务领域。2002年,HP以250亿美元收购了康柏(Compaq),这是当时科技行业最大的一笔收购。这次并购不仅增强了HP在个人电脑市场的竞争力,也推动了公司在服务器、存储设备等多个领域的发展。此外,HP还涉足软件及服务等多个领域,成为一个多元化的科技巨头。通过不断并购和业务拓展,HP在全球科技行业的地位日益稳固。

请注意,虽然问题中提到了Keysight,但Keysight实际上是惠普在2014年从惠普科技公司(HP Inc.)分拆出来的一家独立公司,专注于电子测量和测试解决方案。因此,上述故事主要围绕HP(惠普)公司的发展历史进行描述,并未直接涉及Keysight公司。

Bliley Technologies Inc公司的发展小趣事

随着战争的结束,军事通信市场的需求逐渐减少,Bliley开始寻求新的发展机遇。公司开始将目光投向更广泛的商业应用领域,并逐步拓展其产品线。在20世纪80年代初,Bliley开始生产SC切割晶体,这一创新使其在晶体制造领域取得了新的突破。进入21世纪,Bliley继续加大研发力度,不断推出新的产品和服务。2001年,公司更名为Bliley Technologies Inc.,以更好地反映其日益多样化的产品和服务范围。如今,Bliley已经发展成为一家提供多种频率控制产品的全球领导者。

无锡友达公司的发展小趣事

面对电子行业的快速发展和智能化趋势,无锡友达积极响应,加快智能化转型和升级。公司不仅在产品设计和生产上引入智能化技术,还通过建立智能化管理系统,提升企业的运营效率和产品质量。此外,无锡友达还积极参与各类行业展会和交流活动,与业界同行共同探讨智能化转型的未来趋势。

台湾致强(FORT)公司的发展小趣事

致强科技自2005年成立以来,便专注于高功率、低阻值且低TCR(温度系数)的电阻产品研发与生产。团队由一群具有机电整合、金属材料加工及冶金制程丰富经验的专家组成,他们独立研发出全合金材料的电阻生产制程,这一创新不仅区别于业界常见的厚膜或厚膜贴合金制程,还大幅提升了电阻的性能与稳定性。通过不断的技术迭代,致强科技成功推出了一系列高精度、高功率的合金电阻产品,广泛应用于各类电子产品中,满足了市场对高质量电流检知电阻的迫切需求。

HANA Micron公司的发展小趣事

在电子配件领域,Hama始终保持着对技术创新的追求。公司不断投入研发资源,推出了一系列具有自主知识产权的高精度、高可靠性的检测仪表产品,如激光测距仪、激光柜位计等,广泛应用于钢铁、矿山、化工等行业。这些创新产品不仅满足了客户的多样化需求,也提升了生产效率和产品质量,赢得了市场的广泛认可。同时,Hama还积极拓展国际市场,产品出口到欧洲、美洲、亚洲等多个国家和地区,进一步提升了其国际影响力。

Galaxy ( Bel )公司的发展小趣事

Hama公司成立于1923年,最初在德勒斯登作为一家个人作坊起家,专门批发摄影设备及制造实验室和录音设备。随着电子技术的兴起,Hama敏锐地捕捉到市场变化,开始逐步将产品线扩展到电子配件领域。通过不断的技术研发和产品创新,Hama成功转型为一家电子配件的领军企业,其产品线涵盖了从电线、存储卡、天线到相机配件等广泛品类。这一转型不仅巩固了Hama在市场上的地位,也为其后续的发展奠定了坚实基础。

问答坊 | AI 解惑

开关电源中几种过流保护方式

开关电源中几种过流保护方式…

查看全部问答>

如果delay()过程中,出现软中断会怎么样 ?

代码如下, 已知0x1c中断是个软定时中断, 每隔1/18秒执行一次 setvect(0x1c,new1cv); ...代码 delay(20); //延迟20ms ...代码 其中0x1c中断是一个软定时中断,如果程序在执行delay的20ms内, 正好0x1c中断到了, 程序是等着delay(20)执行完 ...…

查看全部问答>

招WINCE驱动工程师一名

公司现欲招WINCE驱动工程师一名 最好会WIN32应用程序编写 工资多少?我不知道 公司啥名?你加我我告诉你 QQ:502240410 哦对了公司在北京 大家别喷我啊 我也不是职业招人的 临时客串而已......…

查看全部问答>

cmd文件

本帖最后由 dontium 于 2015-1-23 13:30 编辑 我从TI网站上载了一些历程,发现里面的 工程里都有两个CMD文件. DSP281X_Headers_nonBIOS.cmd F2812_EzDSP_RAM_ink.cmd 请问高手,这两个CMD文件都起什么作用? 它们会不会冲突? …

查看全部问答>

avr/51/pic/arm 强强联合 请进

各位单片机爱好者,有兴趣请加入单片机爱好者群:100955523,是大家一起技术交流,技术分享的联盟。。。 …

查看全部问答>

差动放大器——良好匹配电阻器不可或缺的器件

本帖最后由 dontium 于 2015-1-23 12:43 编辑 在单片IC设计过程中,我们常常会竭尽所能地对内部组件进行精确的匹配。例如,精确匹配运算放大器的输入晶体管,旨在获得低失调电压。如果我们必须使用属于我们自己的离散晶体管运算放大器,则我们会得 ...…

查看全部问答>

CC2530技术问题咨询

TI技术工程师:     您好,直入主题,我现在碰到一个问题,想请教您。     现在做的项目是:无线射频(2.4G)CC2530的射频子板,现在投的PCB样机,并找专业人员手工焊接。     原理图和PCB版图基本上是按照德州仪器 ...…

查看全部问答>

multisim的波特图仪的分辨率能设置吗

有哪位神用multisim求教。 这个分辨率太低了怎么设置? 左从48.245调一下直接到了51.979 求指教,这个能改吗?怎么改?我这要求最好0.1格或0.5皆可。 file:///C:/Users/Administrator/AppData/Roaming/Tencent/Users/84246146/QQ/WinTemp/RichO ...…

查看全部问答>

在CCS中如何将数据定义在INFOflash中

各位高手,在CCS中如何将数据定义在INFOflash中。在IAR中可以使用root关键字,不知道在ccs里面如何定义,找不到关于编译器的使用手册。…

查看全部问答>

static和extern的区别

static和extern的区别static: 一、在C中,static主要定义全局静态变量、定义局部静态变量、定义静态函数。 1、定义全局静态变量:在全局变量前面加上关键字static,该全局变量变成了全局静态变量。全局静态变量有以下特点。     & ...…

查看全部问答>