历史上的今天
返回首页

历史上的今天

今天是:2024年09月17日(星期二)

2021年09月17日 | STM8将库函数移植为寄存器方法

2021-09-17 来源:eefocus

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


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


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


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

image.png?imageView2/2/w/550

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

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

image.png?imageView2/2/w/550

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


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

image.png?imageView2/2/w/550

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

image.png?imageView2/2/w/550

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


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

image.png?imageView2/2/w/550

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

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

image.png?imageView2/2/w/550

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

image.png?imageView2/2/w/550

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

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

image.png?imageView2/2/w/550

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

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

image.png?imageView2/2/w/550

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

image.png?imageView2/2/w/550

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

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

image.png?imageView2/2/w/550

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


LED_GPIO_PORT,

(GPIO_Pin_TypeDef)LED_GPIO_PIN,

GPIO_MODE_OUT_PP_LOW_FAST

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


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

image.png?imageView2/2/w/550

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

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

image.png?imageView2/2/w/550

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


接下来看GPIO_Pin

image.png?imageView2/2/w/550
image.png?imageView2/2/w/550

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

image.png?imageView2/2/w/550
image.png?imageView2/2/w/550

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


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


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


下面接着看第三个参数GPIO_MODE_OUT_PP_LOW_FAST

image.png?imageView2/2/w/550

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

image.png?imageView2/2/w/550

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

首先将0xE0转换为二进制

image.png?imageView2/2/w/550

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


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

image.png?imageView2/2/w/550

首先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?imageView2/2/w/550

然后继续判断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?imageView2/2/w/550
image.png?imageView2/2/w/550

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


第一行将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?imageView2/2/w/550

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


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

image.png?imageView2/2/w/550

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


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

image.png?imageView2/2/w/550image.png?imageView2/2/w/550
image.png?imageView2/2/w/550

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


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


将主函数中的代码替换

image.png?imageView2/2/w/550

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


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


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

推荐阅读

史海拾趣

AAT [Advanced Analog Technology, Inc.]公司的发展小趣事

由于版权和实时数据的限制,我无法直接为您提供关于AAT(Advanced Analog Technology, Inc.)公司的5个具体的发展故事。但是,我可以提供一个通用的框架,您可以根据这个框架来查找或编写相关故事。


AAT公司发展故事框架

  1. 创业初期与技术创新

在电子行业的初期,AAT公司由一群富有远见和技术的工程师创立。他们瞄准了模拟技术领域的巨大潜力,决心开发出一系列高性能的模拟芯片。初期,公司面临资金短缺和技术挑战,但通过不断的技术创新和市场调研,AAT成功研发出了一款具有竞争力的模拟芯片,并获得了市场的认可。

  1. 市场拓展与国际合作

随着技术的成熟和产品的完善,AAT开始积极拓展市场。他们与全球多家知名电子企业建立了合作关系,共同推动模拟芯片在各个领域的应用。同时,AAT也积极参与国际技术交流活动,与全球同行分享经验和技术成果,进一步提升了公司的国际影响力。

  1. 应对行业变革与战略调整

随着电子行业的快速发展和变革,AAT也面临着新的挑战和机遇。为了应对这些变化,公司进行了战略调整,加大了对新兴技术的研发投入,并优化了产品结构和市场布局。这些举措使得AAT在激烈的市场竞争中保持了领先地位。

  1. 人才培养与团队建设

AAT深知人才是企业发展的核心。因此,公司一直注重人才培养和团队建设。他们通过提供丰富的培训和发展机会,吸引和留住了一批优秀的工程师和管理人才。这些人才为公司的技术创新和市场拓展提供了有力支持。

  1. 社会责任与可持续发展

在追求经济效益的同时,AAT也积极履行社会责任。他们关注环境保护和可持续发展,通过采用环保材料和节能技术,降低产品对环境的影响。此外,AAT还积极参与公益事业,为社会做出积极贡献。


以上只是一个通用的框架,您可以根据这个框架来查找或编写关于AAT公司的具体发展故事。在编写时,请确保只描述事实,避免加入个人主观评价或褒贬色彩。同时,由于电子行业和AAT公司的发展是一个持续的过程,建议您查阅最新的行业资讯和公司报告,以确保故事的时效性和准确性。

Cressall Power Resistors公司的发展小趣事

Cressall一直注重企业文化建设和团队建设。公司倡导“创新、协作、诚信、责任”的核心价值观,鼓励员工勇于创新、敢于担当。同时,公司还加强了对员工的培训和激励,为员工提供了良好的职业发展平台。这些措施有效提升了员工的凝聚力和归属感,为公司的持续发展提供了有力的人才保障。

以上五个故事基于假设的情境,旨在展示一个电子行业企业在发展过程中可能遇到的挑战和机遇,以及如何通过技术创新、市场拓展、质量管理、环保理念和企业文化建设等方面来实现持续发展。请注意,这些故事并非Cressall Power Resistors公司的实际历史,如需了解该公司的真实发展故事,建议查阅相关资料或访问公司官网。

Frequency Sources公司的发展小趣事

面对日益严峻的环境问题和不断变化的市场需求,Frequency Sources公司积极响应国家环保政策和可持续发展战略,致力于研发绿色、环保、高效的频率源产品。同时,公司还继续加大在技术创新方面的投入力度,不断推出具有自主知识产权的新产品和新技术。这种可持续发展的理念和技术创新的精神使得公司在激烈的市场竞争中始终保持领先地位并实现了持续健康的发展。

需要注意的是,以上故事是基于电子行业的一般情况和频率源技术的特点来构建的虚构故事,并不直接对应任何具体公司的实际情况。在实际应用中,请根据具体公司的历史和发展情况进行调整和修改。

Deltron / DEM Manufacturing公司的发展小趣事

随着公司实力的不断增强,DEM Manufacturing开始积极拓展国际市场。公司凭借优质的产品和专业的服务,成功打入欧洲、北美等多个地区的市场,并建立了稳定的销售网络。同时,公司还积极参与国际展览和论坛,与国际同行进行交流和合作,不断提升自身的国际影响力。

Easy Magnet Corp公司的发展小趣事

Easy Magnet Corp公司最初由几位热衷于磁性材料研究的科学家和工程师创立。他们发现了一种新型磁性材料,具有极高的磁导率和稳定性。基于这一发现,他们开始研发适用于电子产品的磁性元件。最初的产品虽然简单,但因其高性能和可靠性,很快在市场中获得了认可。随着订单的增加,公司逐渐扩大了生产规模,并开始了技术研发的深入探索。

客益(Guestgood)公司的发展小趣事

随着环保意识的提高,Easy Magnet Corp公司开始关注产品的环保性能。公司采用环保材料和生产工艺,减少了对环境的污染。同时,公司还积极参与环保公益活动,倡导绿色消费理念。这些举措不仅提升了公司的社会形象,也吸引了更多注重环保的消费者。

问答坊 | AI 解惑

求周立功esayarm2200开饭板

qq:343979611  开发用到,现求奕块二手的,配套资料要齐全。…

查看全部问答>

怎样评估双口RAM应该使用大小和多少?

1.简单一点根据输入输出的数据多少,并预留一定裕量。 但这个标准时多少,欢迎大家讨论?…

查看全部问答>

有没有谁见过这些触发器。知道它们特性方程吗?

[img=http://hi.eeworld.net/attachment/200911/22/5108_1258896379hB6h.jpg][/img][img=http://hi.eeworld.net/attachment/200911/22/5108_1258896378SHxq.jpg[/img]…

查看全部问答>

有人是用CF2.0开发界面的吗?

可不可以将DataGrid设置每行的高度啊? …

查看全部问答>

SDIO设备驱动的问题

要实现二个SD卡接口(SDIO设备) 是不是要实现以下二套机制 SD Cilent    SD bus SDHC SD卡硬件 SD Cilent    SD bus SDHC SD卡硬件 …

查看全部问答>

gooogleman请进。NAND启动代码问题。

NAND启动代码 ldr r0, =BWSCON ldr r0, [r0] ands r0, r0, #6 ;OM[1:0] != 0, NOR FLash boot bne copy_proc_beg ;don\'t read nand flash\' adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash boot cmp r0, #0 ;if use Multi-ice, 如果使 ...…

查看全部问答>

EM310模块发送数据无应答,求解

在给的开发流程中是这样: AT%IPOPEN=\"TCP\",\"61.144.177.202\",3000 CONNECT AT%IPSEND=\"683100310068c90896060000027400000100e416\" %IPSEND:15 OK %IPDATA:20\"683100310068C90896060000027400000100E416\" ------------------------ ...…

查看全部问答>

关于点阵闪烁和扫描键盘的问题

经过一天的奋斗,,终于把那个贪吃蛇弄好了,但是在效果上还是不足,当蛇身增长后(4个以后)出现了明显的闪烁问题,还有就是扫描矩阵键盘不是很灵敏。矩阵键盘方面我在尝试改成中断,但是点阵闪烁问题怎么解决啊?延时增加亮度的话又担心执行一次循 ...…

查看全部问答>

【视频分享】电源设计小贴士37:折中选择输入电容纹波电流的线压范围

简介:您在为一个低功耗、离线电源选择输入滤波电容时,会出现一种有趣的权衡过程。您要折中地选取电容的纹波电流额定值,以适合电源工作所需的电压范围。通过增加输入电容,您可以获得更多纹波电流的同时还可以通过降低输入电容的压降来缩小电源的 ...…

查看全部问答>

RAW_SEM.C 教学问题

RAW_SEM.C 教学问题 1 raw_semaphore_create教学问题 1 RAW_SEMAPHORE和这个结构体里的RAW_COMMON_BLOCK_OBJECT是什么样的关系,体现了面向对象里面的什么思想? 2初始化后任务默认是以什么样的方式阻塞在semphore 上的? 3 如何改变任务阻塞方式? ...…

查看全部问答>