首页 > 编程知识 正文

stm8s如何添加头文件,寄存器版本和库函数版本

时间:2023-05-03 17:08:35 阅读:170863 作者:2899

使用STM32单片机时,我喜欢使用库函数。 STM32的寄存器过多,如果直接使用寄存器,设置就很麻烦。 另外,STM32单片机速度快、容量大,使用寄存器效率不高。

对于STM8单片机来说,使用寄存器仍然是必要的,其自身的STM8单片机速度与stm32相比慢很多,同时芯片容量也小。 使用库函数的话,会占用空间,系统稍微变大的话芯片容量就不够了,所以STM8单片机经常使用寄存器,STM8的寄存器也少,设定也简单。

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

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

打开LED库函数版的项目。 首先从main函数开始。 第一行代码是系统初始化。

右键单击BSP_Initializes ()函数,然后选择“跳转到函数定义”。

跳到系统初始化代码处。 此初始化代码包含两个函数:用于初始化系统时钟的函数和用于初始化指示灯的端口。

使用以上方法,右键单击并跳转到时钟初始化函数中。

这里面调用了另一个函数,继续右击跳转。

此时,跳转到系统的库函数中。 从这个函数可以看出,此时正在操作CKL_CKDIVR寄存器。

然后在单片机手册中找到该寄存器,发现该寄存器设置了时钟分频值。

我说明时钟初始化的过程是设定时钟的分频值,这个分频值设定了多少?

clk _ hsiprescalerconfig (clk _ prescaler _ HSI div1); 在该行的代码中,右键单击函数括号中传递的参数CLK_PRESCALER_HSIDIV1,然后选择“跳转到定义”。 此参数的值是设置CKL_CKDIVR寄存器的值。

从宏定义中可以看出,传递的参数值设定为0,即CKL_CKDIVR寄存器的值设定为0。

在芯片手册寄存器的说明中,可以看出值为0,即寄存器设定为1分频。

在此基础上,时钟初始化功能可以通过将CKL_CKDIVR寄存器的值设置为0,将系统时钟初始化的代码直接改变为寄存器操作。

clk _ hsiprescalerconfig (clk _ prescaler _ HSI div1); 使用CLK-CKDIVR=0x00屏蔽该行中的代码; 而是重新编译下载以查看指示灯闪烁是否正常。

重新编译下载后,指示灯闪烁正常,表示代码替换暂时没有问题,然后继续替换指示灯初始化部分的代码。

右键单击找到定义,然后单击“向下”。

最后跳到了一个名为GPIO_Init的库函数。 这个库函数的代码很长,设定的寄存器也很多,怎么替换呢?

在这种情况下,需要参数。 相反需要参数。

此GPIO_Init函数具有以下三个参数:

LED_GPIO_PORT,(GPIO_Pin_TypeDef ) LED_GPIO_PIN,GPIO_MODE_OUT_PP_LOW_FAST的第一个参数是GPIO

首先,右键单击LED_GPIO_PORT参数的具体含义

根据宏的定义,端口为GPIOB,有5个针脚,

此时,可以在GPIO_Init函数内部确认GPIOB是否被写入该寄存器。

在代码中看到GPIOx就知道了,这是为了选择设定哪个寄存器,如果在宏定义中设定的GPIOx是GPIOB,那么在GPIO_Init函数中设定的就是GPIOB寄存器。

接下来我们来看看GPIO_Pin

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

ODR寄存器用于设置端口的输出数据,DDR寄存器用于设置IO端口的输入/输出模式。 此处用于驱动LED时,IO端口必须设置为输出模式。

这里一定要将DDR5设为1,也就是将DDR寄存器的第5位设为1,将GPIOB端口的第5个端口设为输出。

ODR寄存器用于控制输出0或1,即LED的闪烁。

现在,我们来看第三个参数GPIO_MODE_OUT_PP_LOW_FAST

此参数的值为0xE0,包括在GPIO_Init函数视图中。

可以看出,该值没有直接设定在寄存器中,而是用于比较不同的位,设定不同的模式。

首先将0xE0转换为二进制

你会发现最高的三位数都是1。

然后在代码中进行分析,判断语句中执行的代码。

首先,gpiox-Cr2=(uint8_t ) ) )~(GPIO_Pin ) );

该行中的代码将执行,然后确定GPIO_Mode的第七位是否为1。 GPIO_Mode最高的第三位都是1,所以条件成立。 进入if语句,然后判断GPIO_Mode的第4位是否为1,GPIO_Mode的第4位是否为0,所以第2个if条件

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

然后继续判断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;



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

第一行将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()函数替换

编译下载程序到单片机中,观察LED闪烁情况,下载完成后LED闪烁正常,说明代码设置也正常。
这样就将CLK_Configuration()函数和GPIO_Configuration()函数都替换为了寄存器版,为了方便观看,将寄存器的相关初始化都放在main函数中。

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


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

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

将主函数中的代码替换

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

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

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

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。