STM32自学周记(一)

STM32自学周记(一)

转眼来到大二下学期,回想过去的一年半,浑浑噩噩,除了必修的课程之外没有获得什么知识。决定从本学期开始,逐步学习STM32单片机以及其他与专业有关的技能知识。

第一天学习的时候在网上到处找资料,看stm32的介绍,看stm32的学习方法,制定计划。学习单片机一定要多动手,代码只看不动手敲一敲什么都记不住,所以当天晚上联系了同学一起买了块迷你开发板。
在开发板邮回来之前以学习理论知识为主,首先是c语言的学习。从头开始学我觉得是来不及的,介于完整的学过c++,便学习32常用的c语言。

一、位操作
&(按位与): 1&1 = 1 1&0 = 0 0&1 = 0 0&0 = 0
~(取反): ~1 = 0 ~0 = 1
|(按位或):1|1 = 1 0|1 = 1 1|0 = 1 0|0 = 0
^(按位异或): 1^1 = 0 0^1 = 1 1^0 = 1 0^0 = 0
<<(左移):将一个数的各位左移n位,低位补0。 00001100 << 2 = 00110000
>>(右移):将一个数的各位右移n位,高位补0。 00001100 >> 2 = 00000011
二、define 宏定义
格式:#define 标识符 字符串
三、 ifdef 条件编译
格式:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
在编写头文件时会用到,目的是为了避免头文件被重复定义。
四、 extern 变量申明
用法如下
Main.c
u8 id;
main()
{
id=1;
printf(“d%”,id);//id=1
test();
printf(“d%”,id);//id=2
}
在该文件中,main已经定义了id,但是test未定义id,这时就用到extern进行变量申明,如下:
extern u8 id;
void test(void)
{
id=2;
}
五、 typedef 类型别名
定义一种类型的别名,可以用作同时声明指针型的多个对象,例如:
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
六、 结构体
Struct 结构体名{
成员列表1;
成员变量2;

}变量名列表
他的意义在于简化了操作,可以在不改变入口参数的情况下,只需要改变结构体的成员变量,就可以达到改变入口参数的目的。
七、static关键字
Static申明的局部变量,它在函数调用结束之后,不会被释放,它的值会一直保留下来,具有记忆功能。例如:
int getValue(void)
{
int flag=0;
flag++;
return flag;
}
每次调用getValue函数,它的返回值都是“1”。
int getValue(void)
{
static int flag=0;
flag++;
return flag;
}
第一次调用getValue函数,它的返回值是“1”;第二次调用,flag的初始值变为1,返回值是“2”;第三次调用返回值是“3”,以此类推。

在掌握了c语言的一些基础之后,便想着手编写第一个程序,但是教程看了几分钟就被一个东西弄的一头雾水,完全看不懂讲的是什么,它就是GPIO系统。于是赶快回过头来学习GPIO的工作原理。
GPIO工作原理
我在网上学习的是STM32 M4,它一共有七组IO口,每组有16个IO,共16*7=112个IO。stm32的大部分引脚出来当做GPIO使用外,还可以复用为外设功能引脚。
下图为GPIO的原理图

在这里插入图片描述
4种输入模式:
(1)输入浮空(1→2→3→4):浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器。 也就是说,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。
(2)输入上拉(1→2→3→4):上拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在高电平;并且在I/O端口输入为低电平的时候,输入端的电平也还是低电平。
(3)输入下拉(1→2→3→4):下拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在低电平;并且在I/O端口输入为高电平的时候,输入端的电平也还是高电平。
(4)模拟输入(1→5):模拟输入模式下,I/O端口的模拟信号(电压信号,而非电平信号)直接模拟输入到片上外设模块。
4种输出模式:
(1)开漏输出(6→7→8→1→2→3→4):当设置输出的值为高电平的时候,N-MOS管处于关闭状态,此时I/O端口的电平就不会由输出的高低电平决定,而是由I/O端口外部的上拉或者下拉决定;当设置输出的值为低电平的时候,N-MOS管处于开启状态,此时I/O端口的电平就是低电平。
(2)开漏复用功能(9→7→8→1→2→3→4)与开漏输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
(3) 推挽式输出(6→7→8/10→1→2→3→4)当设置输出的值为高电平的时候,P-MOS管处于开启状态,N-MOS管处于关闭状态,此时I/O端口的电平就由P-MOS管决定:高电平;当设置输出的值为低电平的时候,P-MOS管处于关闭状态,N-MOS管处于开启状态,此时I/O端口的电平就由N-MOS管决定:低电平。
推挽式复用功能(9→7→8/10→1→2→3→4):与推挽输出模式很是类似。
4种最大输出速度:
(1)-2MHZ
(2)-25MHz
(3)-50MHz
(4)-100MHz
GPIO相关配置寄存器
每组GPIO端口的寄存器包括:

一个端口模式寄存器(GPIOx_MODER)
一个端口输出类型寄存器(GPIOx_OTYPER)
一个端口输出速度寄存器(GPIOx_OSPEEDR)
一个端口上拉下拉寄存器(GPIOx_PUPDR)
一个端口输入数据寄存器(GPIOx_IDR)
一个端口输出数据寄存器(GPIOx_ODR)
一个端口置位/复位寄存器(GPIOx_BSRR)
一个端口配置锁存寄存器(GPIOx_LCKR)
两个复位功能寄存器(低位GPIOx_AFRL & GPIOx_AFRH)

之后便开始学习程序的编写

用库函数编写跑马灯程序
在这里插入图片描述
右侧输入高电平1。
当LED0输出0时,两端有压差,LED0亮;
当LED0输出1时,两端无压差,LED0灭。

重要函数:
1个初始化函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
2设置输出电平函数:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

在学习中,发现需要熟练掌握“右键点击→go to definition of”操作来查看变量定义的使用方法,可以大大缩短时间,而且不容易出错,这个程序几乎都是通过这一操作,复制粘贴已经定义好的变量编写完成的。

首先要调用时钟使能函数RCC_AHB1PeriphClockCmd();然后对该函数进行上面提到的操作(之后称为操作1),进入rcc.h库中,在这里插入图片描述
其后有两个参数,下面的 assert_param() 规定了参数的范围,对( )中的函数进行操作1,就能知道参数的详细范围。在这里插入图片描述如图,
LED0对应IO口是F9,所以这里选择 RCC_AHB1Periph_GPIOF 。
通过上述方法得到了初始化函数

GPIO_InitTypeDef GPIO_InitStructure; // Structure为自定义的函数名

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED0和LED1对应IO口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIOF9,F10
GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);//F9,F10输出高电平

之后就是主函数的编写
int main(void)
{
delay_init(168); //延时函数初始化
while(1)
{
GPIO_SetBits(GPIOF,GPIO_Pin_9 );
GPIO_SetBits(GPIOF,GPIO_Pin_10 );
delay_ms(500);//延时500毫秒
GPIO_ResetBits(GPIOF,GPIO_Pin_9 );
GPIO_ResetBits(GPIOF,GPIO_Pin_10 );
delay_ms(500);//延时500毫秒
}
}
主函数的编写和51单片机类似,也是通过while循环不断的给小灯输入高低电平,实现小灯的闪烁。

以上就是本周的学习内容
由于还没有开发板,没有进行实际的操作。自学一样东西比我想象中的困难多了,一个40分钟的教学视频需要花费2个小时甚至3个小时才能把讲述的每个知识点弄清,没有听懂就反复看。有时候因为一个知识点不理解就要卡住1个小时,期间还要专门查阅资料,等到理解之后回过头来继续学习,还要把之前讲过的再复习一遍。发现通过画示意图的方法能提高记忆力。让我意外的是写这篇博客也花费了好多时间,写的过程中重洗梳理了思路,之前学习的东西在脑中变得更加清晰,加深了印象,把知识巩固了一遍。把学到的东西整理下来的确很有必要啊。
开发板下周就会收到,相信通过实际操作,会有更多的收获和体验。

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值