STM32单片机初学心得

一个小阶段下来收获颇丰,经过复盘,整理相关笔记如下。(本早该发布一直拖到了现在)

1. 关于延时效果除了HAL_Delay外常用的方法

在这个阶段中做了一个小项目——楼道灯。

因为还未接触到继电器,所以这个小项目是以代码实现的,配置好相应硬件后开始编写代码,其中要实现一个让灯亮的中断条件,这个问题定义几个变量并判断大于或小于某个值、或是处于某个状态就可解决。

此外,要实现楼道灯亮一定时间后自动熄灭的效果,在此考虑的问题较多。在这里的代码实现里,我们在点灯的时候记录当前时间,然后循环获取当前时间看有没有超时,如果超时则控制关灯。

Part1.

实现这一功能作为初学者的自己开始想到的是直接调用HAL_Delay函数进行直接延时,后边在老师指导下才知道,HAL_Delay函数的确可以在这个项目中达到效果,但其实它是低效的,因为用HAL_Delay函数直接延时的话,程序就不能再做其它的控制,其他操作无法进行了。

Part2.

在判断时间是否到没有,我们不能直接用类似   if( (HAL_GetTick()   -   start)   >  3000 )这样的条件判断( 3000是3000ms的意思 ),因为变量的最大记值是有限制的( uint32_t 最大计数到2^32-1 ),而时间是无限的,这样会存在时间回绕的问题。

【PS:   但在如果给出的问题类似 “ 在 xx ms内实现XX操作” 时就可用 if((HAL_GetTick()  -  start)   >  3000 )这样的条件判断,这时这样的判断语句是最常用的。】

Part3.


这里我们参考Linux内核里的jiffies , 回绕解决方案,使用了time_after()这个宏来判断是否超时。这个宏我们需要添加到main.h头文件中。

楼道灯部分代码:

int main(void)
{
    uint32_t   lux, noisy;
    uint32_t   start = 0;
    uint8_t    light_status = 0;

    while (1)
    {
	    if( OFF == light_status)
	    {
		    adc_sample_lux_noisy(&lux, &noisy);
		    printf("Lux[%lu] Noisy[%lu]\r\n", lux, noisy);

		    if( lux<30 && noisy>800)
		    {
			    turn_led(BlueLed, ON);
			    //turn_relay(Relay2, ON);  //继电器
			    light_status = ON;

			    /* record current time and will turn off in 3  seconds */
			    start = HAL_GetTick();
		    }
	    }
	    else
	    {
		    if( time_after(HAL_GetTick(), start+3000) )
		    {
			    turn_led(BlueLed, OFF);
			    //turn_relay(Relay2, OFF);  //继电器

			    /* must give delay for turn relay off got noisy , it will affect next 
    sample  */
			    HAL_Delay(200);

			    /* set light status as OFF  */
			    light_status = OFF;
		    }
	    }

	    HAL_Delay( 10 );  //在这里可以进行别的希望进行的操作

   }
}

2.杂

(1)切换1、0对应状态可相应左右移动,后再进行位运算调整。

(2)datasheet对应用到的需更深研究地进行学习效果更好。

(3)不知道的函数之类的不必死扣,百度关键字搜索。

(4)中断向量表里每一个中断服务处理程序都是4个字节,因为32位cpu字长是4个字节(.word),且要按4个字节来补齐,一个中断4个地址存放,中断号不存在或者无用不能删掉,要补0。

(5)函数返回值类型为_weak 说明该函数是可以被重写的,但_weak一定不能不写。

(6)只需1个位控制的只需低16个管脚,而2个位的需32个管脚。

(7)GPIOx_IDR知道管脚当前是高/低电平(先读这个寄存器再获取这个管脚位的值,获取位值:右移当前要看的管脚位,然后做相应取反,看最后输出是1是0),GPIOx_ODR设置一个管脚输出高/低电平(如果设置高电平就用1 或上 1的左移当前管脚序号;低的话就先重复设置高电平的操作,然后再),GPIOx_BSRR控制某一个管脚。(其他寄存器去看datasheet)

猜你喜欢

转载自blog.csdn.net/qq_51368339/article/details/119575520