菜喵のSTM32F4学习笔记(0)

(讲道理第一篇似乎应该来个开场白,不过那不重要,就不要了)
这篇文章几乎没有怎么润色,大约保留了自己学习过程中的原始笔记和debug记录,部分内容甚至很基础,bug出的也很没水平,大家笑一笑就好2333。
注1:本次笔记中使用STM32F407ZGT6,利用STM32库函数进行开发;
注2:个人笔记,记录的是零散的知识,不对涉及到的背景知识进行的铺开介绍(换句话说这不是一个成体系的可以视作学习用的教材的笔记~);
注3:啥时候B站专栏有代码块和公式啊qwq。
2020-8-22自学笔记(PS:基础不牢,地动山摇,嵌入式的深入理解还是补一补好,所以之前的试验,再来一遍(笑))

试验1:按键输入试验
debug1:
昨天的bug,我定义了LED的初始化函数,但是在主程序里没有调用,可喜可贺,愚蠢至极。
这么蠢的bug是没有任何描述的。

debug2:
今天打算写一个按键控制RGB灯的试验,定义了如下的按键扫描函数(PS:这部分参照了正点原子的按键输入试验代码,略作小改动):
int KeyScan(int mode); //具体的内容我写在最后了。
返回值为1、2、4(分别对应于KEY1按下、KEY2按下、KEY1与KEY2同时按下的情况)还有0(KEY1、KEY2都不按下)。

为了不像正点原子那样写一串的switch判断,同时为了试一试位运算,主程序的while(1)里我是这样写的:


LED点亮函数如下:

注意这里的mode,之前我写的是:
if(mode == 1)
但是除了红灯LED_R以外,main函数中余下的与运算得到的是2、4;除非进行移位操作,不然没有效果,所以吧==1去掉了。
#ps:将主函数中的while内容改成如下代码即可继续用if(mode == 1),虽然没必要吧:


debug3:
原始代码:

返回值1、2、4分别对应了RGB三个颜色的灯,但是在观察的时候发现,按下KEY2后,绿色只闪烁了一下之后就灭了(理论上应该如此,因为主函数的延迟时间很短,只有10ms),而其他的灯却可以常亮(事实上我没有开启这个功能)
回看代码发现标红的部分存在比较大的问题。
等于的运算判断是要比或运算优先级高的,所以先判断了KEY2 是否为零,如果是按下当然要返回一个0,KEY1这时候不按下,为0。两者取与,为0 ,不会执行key_up = 1这条语句。
而对于余下的两个返回值1、4,由于都有KEY1的按下,本行中1与KEY== 0 的结果与运算,一定为1 ,故而出现了长按的bug。(你这编程都咋学的?这也能忘?)

Code:
这里是以上debug对应的最后修改程序,实现了按下按键灯亮一秒,长按无效的操作。
不过因为判断时间是1s,所以不是每次按下都会有反应(PS:所以大家轻易不要用轮询2333,中断函数和RTOS任务他不香吗(笑);当然,测试程序自己知道咋回事的时候,轮询挺好的,嗯)。
main.c文件:(再次小吐槽一下B站专栏没有代码块的事r(笑))
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#define KEY_1 GPIO_Pin_0
#define KEY_2 GPIO_Pin_1
#define KEY1 GPIO_ReadInputDataBit(GPIOD,KEY_1)
#define KEY2 GPIO_ReadInputDataBit(GPIOD,KEY_2)
void InitLED()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
void InitKey()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
void LED_R(int mode)
{
if(mode)
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
else
GPIO_SetBits(GPIOD,GPIO_Pin_2);
}
void LED_G(int mode)
{
if(mode)
GPIO_ResetBits(GPIOD,GPIO_Pin_3);
else
GPIO_SetBits(GPIOD,GPIO_Pin_3);
}
void LED_B(int mode)
{
if(mode)
GPIO_ResetBits(GPIOD,GPIO_Pin_4);
else
GPIO_SetBits(GPIOD,GPIO_Pin_4);
}
int KeyScan(int mode)
{
static int key_up;
if(mode)key_up =1;
if(key_up&&(KEY1==1||KEY2==1))
{
delay_ms(10);
key_up = 0;
if(KEY1 == 1 && KEY2 != 1)return 1;
else if (KEY1 != 1 && KEY2 == 1)return 2;
else if (KEY1 == 1 && KEY2 == 1)return 4;
}
else if((KEY1||KEY2) == 0) key_up = 1;
return 0;
}
int main(void)
{
u32 flag=0;
uart_init(115200);
delay_init(168);
InitLED();
InitKey();
while(1){
flag = KeyScan(0);
LED_R(flag & 0x01);
LED_G(flag & 0x02);
LED_B(flag & 0x04);
delay_ms(1000);
printf("%d\n",flag);
}
}
试验2:按键输入试验(改)
这部分在每个LED_X(int mode)函数中定义了静态变量用于保存当前灯状态,代码如下:

除了加粗的地方以外,LED_G() 和 LED_B()余下的部分与红色LED相同。
//关于状态取反的微操:
state = -(state - 1); //0、1两个状态的切换
或者这样(取反):state = ~state;
当然你也可以写在state的if else语句当中,不过大括号会让你的代码变长。篇幅太长的话个人感觉不是很好看。

附一张接线图:从上到下就是KEY1和KEY2,输入用的是3.3V的电平。
为了方便,GPIO用的是GPIOD的0-4五个端口,Pin0 Pin1作为输入,Pin2~4为R、G、B的输入,低电平有效(我用的RGBLED是共阳的)


关于GPIO的操作笔记大概就这么多,这篇不涉及关于复用的内容,对于GPIO中的各种寄存器、地址等内容也没有涉及(换句话说,最需要深入了解的内容我没放到这个笔记当中,记在纸上了,懒得搬(笑))
emmm,如果有空我也整理一下好了,毕竟这些才是嵌入式的浪漫(?),不然能用Arduino解决的事情干满要麻烦STM32呢(咕)