前言:
好长时间没有写过专业性的博客了,一直在看书,书也由于太深奥看不太懂,近来由于追喜欢的女孩子失败了,唉,伤心欲绝,肝肠寸断,痛哭流涕,泣不成声啊,最终彻悟,女孩子只会影响我拔刀的速度,便下定决心投入学习,此时回首才猛然想起研二快要开题了,不能连板子都不会用,所以开始做起了嵌入式实验,重操旧业。
一、连接板子
连接板子使用的是还是老工具,如下图所示:
将板子连接好之后,双击打开软件:
点击Connect连接开发板。
此时就可以关闭软件了。
二、新建工程
由于我也是新手,能按照满是错误的实验指导书来,并且做出正确的实验,就已经很不错了。
新建工程使用的是:
打开软件:
新建工程:
选择自己开发板的板子,由于我们的板子是F407的,我就选的这个型号。其中的MCU的意思是:微型控制器单元。选择完成后点击OK
三、设置管脚
进入如下界面,接下来的操作,我也不是很理解,单能说出个大概:
这是一个芯片,就是F407,做这个实验,就是要看电路,这个芯片的正确的电路图如下图所示:
这就是贼坑人的一点了,实验指导书,妈的,它的电路图是错误的,如果按照之前的电路图来说,只亮三个灯,恶心,PE2管脚的灯不亮,因为错误的电路图上,这个管脚是PF7,亮个屁啊,连电路都不对。
有了电路图,可以看出是低压亮灯。并且在芯片上找到对应的管脚,并设为OUTPUT模式。
四、时钟树配置,配置外部时钟
在左侧外设一栏中选择RCC:
这个RCC是一个系统时钟,其中选用了HSE高速外部时钟,具体的指望我短时间了解,怕是不太行了,我贴上一个很详细的博客吧!【STM32】系统时钟RCC详解(超详细,超全面)
选完之后,可以看到芯片上这俩个管脚亮了:
我觉得意思应该是OS_CLOCK_IN和OS_CLOCK_OUT,因为这是一个高速外部时钟,应该是要有进有出的吧,,,
接下来就是我的个人理解了,因为是自学,我感觉我理解的是对的,哈哈哈
首先看F407的外设图:
额,浅要理解吧,我们需要的是GPIO外设,GPIO外设是在AHB总线上,并且要求168MHZ,所以时钟配置图来了
点击配置时钟标签,进入配置时钟界面:
说一下下吧,首先左侧输入的频率是25MHZ,是HSE高速外部时钟,所以后面那个PLL Source当然要选择HSE,之后的一顿乘除,我感觉写啥都可以,只要凑够168MHZ的时钟就行,之后作为PLLCLK时钟进行输入,产生了系统时钟168MHZ,然后AHB的预定为168MHZ,之后的那个红框框里面的/4 /2,我个人觉得只是为了凑后面的MAX MHZ而已,我们真正的目的只是AHB就可。
五、外设详细参数设置
点击菜单栏上的Configuration
显示如下,说实话,我也不知道咋用,感觉就是简简单单的配置一下外设就可以了
点击GPIO可以查看我们选定的,指定功能要用的管脚:
可以看到用到了4个管脚,对于每个管脚,我们都可以进行管脚的模式、速度、上拉下拉之类的进行配置,现在这个工程实验里面不需要配置。
这时候就可以点击Generate生成工程代码了,其实说实话,我感觉Cube就是一个图形化编程软件,他把整个工程的大概框架以图形化的形式展现出来,这样生成的代码,最后只需要添加业务逻辑代码就可以了,其他的配置都在Cube中配置完了。
点击生成工程文件。
点击OK,生成文件。
六、添加业务逻辑代码,编译工程
选择Open Project,进入Keil5的工程界面:
然后其实我们主要写的就是main.c文件里面的业务逻辑了
点开main.c
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET);
Turn_On_LED(count % 4);
count++;
HAL_Delay(500);
编写 Turn_On_LED(uint8_t LED_NUM)
void Turn_On_LED(uint8_t LED_NUM)
{
switch(LED_NUM)
{
case 0:
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET);
break;
case 1:
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8, GPIO_PIN_RESET);
break;
case 2:
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_RESET);
break;
case 3:
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_RESET);
break;
default:
break;
}
}
编写完成后,点击编译
编译完成后,点击LOAD到板子上:
七、运行
下载到板子上之后,需要点击一下reset复位键(其实也可以不点,只需要在下面的图标里面设置一下就可以了)
点击复位键后,板子开始运行代码,如图:
八、详细分析源代码(重点)
说是详细分析,其实我也是个大菜逼,只是分析一下main.c中的函数叭
-
HAL_Init();
右击函数名,点击进入函数具体定义页面,这里的HAL,是Hardware Abstraction Layer(硬件抽象层):HAL_StatusTypeDef HAL_Init(void) { /* Configure Flash prefetch, Instruction cache, Data cache */ #if (INSTRUCTION_CACHE_ENABLE != 0U) __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); #endif /* INSTRUCTION_CACHE_ENABLE */ #if (DATA_CACHE_ENABLE != 0U) __HAL_FLASH_DATA_CACHE_ENABLE(); #endif /* DATA_CACHE_ENABLE */ #if (PREFETCH_ENABLE != 0U) __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); #endif /* PREFETCH_ENABLE */ /* Set Interrupt Group Priority */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */ HAL_InitTick(TICK_INT_PRIORITY); /* Init the low level hardware */ HAL_MspInit(); /* Return function status */ return HAL_OK; }
这个函数说实话,我看不懂,我只知道那个NVIC是嵌套中断控制器,详情见这篇博客:STM32中的NVIC详解 至于其他的函数逻辑,目前确实不太懂
-
void MX_GPIO_Init(void)
这个函数是GPIO的初始化函数,当初GPIO的初始化,通过Cube来设置的,就是查看详细外设参数那里,这里是,生成的代码层次的实现:void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOE_CLK_ENABLE();/*使 能 管 脚 E F H 的 时 钟*/ __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10, GPIO_PIN_RESET); /*Configure GPIO pin : PE2 */ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /*Configure GPIO pins : PF8 PF9 PF10 */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); }
__HAL_RCC_GPIOE_CLK_ENABLE();这个宏定义的含义就是使能GPIO的时钟。至于详细的操作了哪个寄存器,我目前还没分析过。
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET);GPIO管脚的输出值的设置,其函数具体内容如下:
由简介看到这个函数操作的是BSRR寄存器,在板子的参考手册中有:
可以看到高位是用来复位的,低位是用来置位的,有上面函数代码逻辑可知,如果函数传入的不是RESET(复位)的话,就认为是置位,由上图可知,对应位为1的话,则对ODRx寄存器进行置位操作,所以这个寄存器相当于一个标志数组的概念,用来进行标志。在进行复位的时候,是将传入的uint16数值强转为32位的,然后左移16位,进行寄存器复位部位的赋值操作。ODRx寄存器的说明如下:
ODR寄存器是端口的输出数据,因为端口都是电路,其实就是输出电压而已,举个例子,在Turn_On_LED函数中,点亮一个LED需要使用RESET复位操作,也就是需要将ODR中的某一位复位,那么复位就会时灯亮,而灯亮是低电压才亮,所以复位的话,就是如上的0x0000 0000就是在对应端口输出低电压。最上面代码的这个部分:
/*Configure GPIO pin : PE2 */ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
就是对管脚的配置初始化信息,如上,初始化管脚位PIN2,模式位PULL/PUSH,然后NO PULL & NO PUSH,速度为LOW,都是当初在Cube中设置过的。至于 HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); 这个函数,目前功力尚浅,看的我眼花缭乱。
-
接下来就是最简单的while部分
可以明显的看到,一开始是将所有管脚设为SET,高电压模式,所有灯都不亮,然后点亮一个灯,如此循环。 -
void Turn_On_LED(uint8_t LED_NUM)
这个目前来说就非常简单了叭,就是一个switch/case语句加上一个RESET输出低电压点亮灯的过程。
九、总结
行了,说了这么多,终于说完了,总结一下吧,主要还是对于硬件的理解太少,因为之前我一直致力于软件工程,看我以前的博客就知道,我是纯软件,没想到硕士变成了嵌入式,害,重新来过吧,一点点的开始学习叭,加油!!!