STM8将库函数移植为寄存器方法

发布者:Weasel最新更新时间:2021-09-17 来源: eefocus关键字:STM8  库函数  移植  寄存器 手机看文章 扫描二维码
随时随地手机看文章

在使用使用STM32单片机的时候,喜欢使用库函数,由于stm32的寄存器太多了,如果直接使用寄存器的话,设置起来太麻烦了,而且stm32单片机速度快,容量大,使用寄存器要额提高不了多少效率。


对于STM8单片机来说使用寄存器还是很有必要的,本身stm8单片机的速度相比于stm32就会慢很多,同时芯片容量也比较小,使用库函数的话,比较占用空间,导致系统稍微大一点,芯片容量就不够用,所以在stm8单片机上,使用比较多的就是寄存器,stm8的寄存器也比较少,设置起来也比较简单。


但是好多stm8单片机的例程都是库函数版的,那么如何将库函数版的代码移植为寄存器版的呢?


这里使用LED闪烁的库函数代码来说明

image.png

打开一个LED库函数版的工程,首先从main函数开始,第一行代码就是系统初始化。
image.png

在BSP_Initializes()函数上单击鼠标右键,选择跳转到函数定义。

image.png

这时就会跳转到系统初始化代码处。这个初始化代码里面有两个函数,一个是初始化系统时钟,一个是初始化LED的端口。


用上面的方法,单击鼠标右键,跳转到时钟初始化函数里面。

image.png

这里面又调用了一个函数,那么继续使用右键跳转。

image.png

这时候就会跳转到系统的库函数里面来了,通过这个函数可以看出,此时操作的是CKL_CKDIVR寄存器。


然后在单片机手册中找到这个寄存器,可以看到这个寄存器是设置时钟分频值的。

image.png

说明时钟初始化的过程就是设置时钟分频值,那么这个分频值设置的是多少呢?

在CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); 这一行代码中,函数括号里面传递的参数CLK_PRESCALER_HSIDIV1,然后鼠标右键,选择跳转到定义。这个参数的值,就是设置CKL_CKDIVR寄存器的值。

image.png

通过宏定义可以看出,传递的参数值是0,也就是说设置CKL_CKDIVR寄存器的值为0.

image.png

通过芯片手册寄存器的介绍中可以看出,值为0,也就是寄存器设置为1分频。

既然知道了,时钟初始化的功能就是将CKL_CKDIVR寄存器的值设置为0,那么就可以系统时钟初始化的代码直接改为寄存器操作。

image.png

直接将CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); 这行代码屏蔽掉,然后使用 CLK->CKDIVR = 0x00;代替,下来重新编译下载,看一下LED灯的闪烁是否正常。

重新编译下载,LED灯闪烁正常,说明代码的替换暂时没有问题,接下来继续替换LED初始化部分的代码。

image.png

使用右键查找定义,依次向下查找。

image.png

最后跳转到了GPIO_Init这个库函数中,这个库函数代码比较长,设置的寄存器也比较多,那么要如何替呢?

这时候需要一个参数,一个参数来替换。

image.png

这个GPIO_Init函数有三个参数,分别是:


LED_GPIO_PORT,

(GPIO_Pin_TypeDef)LED_GPIO_PIN,

GPIO_MODE_OUT_PP_LOW_FAST

第一个参数是设置GPIO端口,第二个参数是设置端口引脚,第三个参数是设置端口模式。


首先使用右键查看LED_GPIO_PORT这个参数的具体含义

image.png

通过宏定义可以看到,端口是GPIOB,引脚是5脚,

这时候就可以在GPIO_Init函数内部查看GPIOB是写入了那个寄存器。

image.png

在代码代码中查看GPIOx可以看到,这个是用来选择设置哪个寄存器的,宏定义中设置的GPIOx为GPIOB,那么GPIO_Init函数中设置的就是GPIOB寄存器。


接下来看GPIO_Pin

image.png
image.png

GPIO_PIN_5的值是0x20,在GPIO_Init函数中设置了GPIPOB的ODR寄存器和DDR寄存器。

image.png
image.png

ODR寄存器用于设置端口的输出数据,DDR寄存器用于设置IO口的输入输出模式,这里用于驱动LED,那么IO口肯定要设置为输出模式。


那么这里肯定设置的是DDR5为1,也就是将DDR寄存器的第5位设置为1,将GPIOB口的第5个口设置为输出。


ODR寄存器用于设置输出0还是1,也就是用来控制LED亮灭的。


下面接着看第三个参数GPIO_MODE_OUT_PP_LOW_FAST

image.png

这个参数的值为0xE0,带入到GPIO_Init函数查看。

image.png

可以看到这个值并没有直接设置给寄存器,而是用来比较判断不同的位,设置不同模式的。

首先将0xE0转换为二进制

image.png

可以看到最高的3位数都是1.


然后在代码中分析,在判断语句中哪些代码会执行。

image.png

首先GPIOx->CR2 &= (uint8_t)(~(GPIO_Pin));

这行代码会执行,然后判断GPIO_Mode第7位是不是1,由于GPIO_Mode最高的3位都是1,所以条件成立。进入if语句,然后判断GPIO_Mode的第4位是不是1,GPIO_Mode的第4位是0,所以第二个if条件不成立。执行

GPIOx->ODR &= (uint8_t)(~(GPIO_Pin));这行代码。接下来执行 GPIOx->DDR |= (uint8_t)GPIO_Pin;

image.png

然后继续判断GPIO_Mode的第6位和第5位是不是1,GPIO_Mode的第5位和第6位都是1,所以执行

GPIOx->CR1 |= (uint8_t)GPIO_Pin; GPIOx->CR2 |= (uint8_t)GPIO_Pin;

这两行代码

将上面执行的代码整理后如下所示


GPIOx->CR2 &= (uint8_t)(~(GPIO_Pin));

GPIOx->ODR &= (uint8_t)(~(GPIO_Pin));

GPIOx->DDR |= (uint8_t)GPIO_Pin;

GPIOx->CR1 |= (uint8_t)GPIO_Pin;

GPIOx->CR2 |= (uint8_t)GPIO_Pin;`


分析后发现这三行代码会执行

然后将参数中的值替换为宏定义中的值


 GPIOB->CR2 &= (uint8_t)(~(0x20));

 GPIOB->ODR &= (uint8_t)(~(0x20));

 GPIOB->DDR |= (uint8_t)0x20;

 GPIOB->CR1 |= (uint8_t)0x20;

 GPIOB->CR2 |= (uint8_t)0x20;

image.png
image.png

通过代码和寄存器可以分析出,


第一行将CR2寄存器的第五位清零,也就是设置最大输出速度为2MHz。


第二行将ODR寄存器第五位清0,输出为0。


第三行将DDR寄存器第五位设置为1,也就是设置为输出模式。


第四行将CR1寄存器第五位设置为1,设置IO口为推挽输出模式。


最后一行将CR2寄存器设置为1,设置IO口的最大输出为10Mhz


由于寄存器复位后的默认值都为0,所以前两行的设置可以不要,只需要后面三行的设置代码就行,那么GPIO_Init()函数最终就可以简化为下面三行代码:


 GPIOB->DDR |= (uint8_t)0x20;

 GPIOB->CR1 |= (uint8_t)0x20;

 GPIOB->CR2 |= (uint8_t)0x20;


然后用这三行代码将GPIO_Init()函数替换

image.png

编译下载程序到单片机中,观察LED闪烁情况,下载完成后LED闪烁正常,说明代码设置也正常。


这样就将CLK_Configuration()函数和GPIO_Configuration()函数都替换为了寄存器版,为了方便观看,将寄存器的相关初始化都放在main函数中。

image.png

这样将所有的初始化代码就放在main函数里面,看起来就更方便了,通过寄存器将刚才一大堆系统初始化工作简化为4行寄存器设置的代码。这样程序执行起来的效率就更高效了。


同样可以将while语句里面的LED控制,也改为寄存器操作。

image.pngimage.png
image.png

LED_ON 可以替换为 GPIOB->ODR |= (uint8_t)0x20;


LED_OFF 可以替换为 GPIOB->ODR &= (uint8_t)(~0x20);


将主函数中的代码替换

image.png

重新编译下载,LED灯正常闪烁,说明代码替换是成功的。


这样通过一步步进入库函数,然后使用寄存器一行一行替换库函数,每替换一个就重新编译下载,观察测试结果,直到所有的代码都替换完。


STM8每个功能的寄存器都比较少,替换起来的时候还是比较快的,如果熟悉的话,一个库函数代码,几分钟就可以全部替换为寄存器代码了。每个功能设置的步骤基本都是一样的,一旦一个功能替换完成,以后遇见类似的库函数代码,直接就可以用以前替换好的寄存器代码去替代。比如初始化IO口,一般都是设置DDR、CR1、CR2这三个寄存器,所以如果遇到了IO初始化的库函数代码,直接用这个三行代码去替换就行,就不用进入到库函数中一行一行代码去分析了。

关键字:STM8  库函数  移植  寄存器 引用地址:STM8将库函数移植为寄存器方法

上一篇:STM8单片机 ADC模拟看门狗中文资料错误
下一篇:STM8单片机 PWM无波形输出解决方法

推荐阅读最新更新时间:2024-11-01 20:25

有关I2C占空比寄存器设置问题
疑问: ----------------------------------------------------------------------- I2C0SCLH = (Fpclk/fi2c + 1) / 2; I2C0SCLL = (Fpclk/fi2c)/2; 在I2C0SCLH = (Fpclk/fi2c+ 1) / 2;里, 为什么是Fpclk/fi2c + 1而不是Fpclk/fi2c? ----------------------------------------------------------------------- 解答: *************************************
[单片机]
U-Boot移植(19)新移植到ylp2410上u-boot的功能
新u-boot-1.1.6-new的功能: 1、同时支持S3C2410和S3C2440 2、支持串口xmodem协议 3、支持USB下载,可以在PC上使用dnw传数据 4、支持网卡芯片dm9000aep 5、支持NAND Flash读写 6、支持从Nor/Nand Flash启动 7、支持烧写yaffs文件系统映象 8、可以直接下载到内存运行 9、支持CFI、Jedec接口的Nor Flash 10、把环境参数保存在nand flash中 11、u-boot把分区设为: define MTDPARTS_DEFAULT mtdparts=nandflash0:256k@0(bootloader), 12
[单片机]
浅谈ATmega 16单片机的T/C0控制寄存器和T/C1控制寄存器
  T/C0相关   1.TCCR0——T/C0控制寄存器   FOC0 WGM00 COM01 COM00 WGM01 CS02 CS01 CS00   位7——FOC0:强制输出比较位。   FOC0仅在WGM[01:00]设置为非PWM模式时才有效。为了保证与未来器件的兼容性,在使用PWM时,写TCCR0要对其清零。对其写1后,将立即进行比较操作。比较匹配输出引脚OC0将按照COM[01:00]的设置输出相应的电平。要注意FOC0类似一个锁存信号,真正对强制输出比较起作用的是COM[01:00]的设置。FOC0不会引发任何中断,也不会在利用OCR0作为TOP的CTC模式下对进行清零的操作。读FOC0的返回值永远为0。
[单片机]
浅谈ATmega 16单片机的T/C0控制<font color='red'>寄存器</font>和T/C1控制<font color='red'>寄存器</font>
Microwindows在基于单片机嵌入式系统中的移植
引言 microwindows是由gregory haerr组织的一个开放源码项目,是嵌入式系统中广泛应用的一种图形用户接口(gui),该项目的目标是在嵌入式linux平台上提供与普通个人电脑类似的图形用户界面。作为x_windows的替代品,microwindows提供了和x_windows类似的功能,但是却占用很少的内存,根据用户的配置,microwindows占用的内存资源只有100kb~600kb左右。microwindows的核心是基于显示设备接口的,可移植性较强,其本身提供了多种嵌入式系统常见的显示设备驱动程序。目前新版本的microwindows已经内建了framebuffer,因此可以不局限于linux
[单片机]
Microwindows在基于单片机嵌入式系统中的<font color='red'>移植</font>
MSP430设置基本时钟系统
简介:上电复位后默认XT2关,ACLK来自XT1,MCLK和SMCLK都来自DCO。 掌握通过对寄存器的操作分配时钟信号: 设置ACLK来自XT1,MCLK来自XT2,SMCLK来自XT2。 各个时钟通道的分频自定。 通过这些基本的时钟模块,我们可以得到3个有用的时钟信号: ACLK辅助时钟(Auxillary Clock) ACLK是LFXT1CLK时钟源经1、2、4、8分频后得到的。 ACLK可由软件选择作为各个外围模块的时钟信号,一般用于低速外设。 MCLK主系统时钟(Main System Clock) MCLK可由软件选择来自LFXT1CLK、XT2CLK、DCOCLK三者之一,然后经1、2、4、8分频。 MCL
[单片机]
多路端口可编程霓虹灯及彩灯控制器
   现有的霓虹灯以及彩灯控制器多是使用专用集成电路,其中固化多种闪烁方式,一般只提供4~16路输出。由于在大型霓虹灯中使用的控制器路数相当多,一般只能定做,代价高而且灵活性较差。本设计由于采用了力源公司的新一代BASIC单片机PS1016及高性价比的8位LED控制驱动器PS7219,从而可实现多路端口,并且能够对任一端口进行控制,可广泛用于大型霓虹灯、塑料霓虹灯以及彩灯的可编程控制,既可在产品上直接编程,又可在计算机上调试好直接传输。具有设计简单、使用方便等特点。 1主要器件介绍 1.1 PS1016单片机   PS1016单片机引脚排列如图1所示,其特点如下:   1.固化在芯片内部的PICBAS
[单片机]
51特殊功能寄存器data
一:中断允许寄存器 IE CPU对中断系统所有中断以及某个中断源的开放和屏蔽是由中断允许寄存器IE控制的。 EX0 (IE.0),外部中断0允许位; ET0 (IE.1),定时/计数器T0中断允许位; EX1 (IE.2),外部中断0允许位; ET1 (IE.3),定时/计数器T1中断允许位; ES (IE.4),串行口中断允许位; EA (IE.7), CPU中断允许(总允许)位。 IE寄存器可进行位寻址,所以可单独操作各个位 例如要操作第零位,直接给EX0赋值即可 二:中断优先级控制 IP PX0(IP.0),外部中断0优先级设定位; PT0(IP.1),定时/计数器T0优先级设定位; PX
[单片机]
51特殊功能<font color='red'>寄存器</font>data
ARM寄存器的操作方法
#define GPIOCOUT *((volatile unsigned int *)0xc001c000) #define GPIOCOUTENB *((volatile unsigned int *)0xc001c004) #define GPIOCALTFN0 *((volatile unsigned int *)0xc001c020) void delay(unsigned int); void led_test(void) { /*配置选择GPIOC12管脚的功能1*/ GPIOCALTFN0 &= ~(3 24);//清0 bit24 25 GPIOCALTFN0 |= (1 24);//置1
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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