达成成就:点灯大师!!! 记录下学到的一些要点
操作 GPIO 步骤分解
总共涉及了
RCC和GPIO两个外设
- 使用
RCC开启GPIO的时钟- 使用
GPIO_Init函数初始化GPIO- 使用输出或者输入的函数控制
GPIO口两个外设的库函数
RCC最主要的只有三个函数:RCC AHB外设时钟控制 ||RCC APB2外设时钟控制 ||RCC APB1外设时钟控制
GPIO最主要的是GPIO_Init和八个读写函数
点亮 LED 代码
#include "stm32f10x.h" // Device header int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_ResetBits(GPIOA, GPIO_Pin_0); while (1) { } } 这里学到了一些新东西,主要在第一行
RCC开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);可以翻译成:请RCC给 APB2 总线上的 GPIOA 外设 打开时钟,让它开始工作
RCC的三个函数RCC_AHBPeriphClockCmd、RCC_APB1PeriphClockCmd、RCC_APB2PeriphClockCmd表示的是要开启时钟的外设在哪条总线上不记得没关系,可以跳转到定义查看,以
RCC_APB2PeriphClockCmd为例,其定义如下(可以看到 GPIOA 外设在这上面)
时钟是给外设的,不是给某个引脚的。这里我们要操作的是
GPIOA上的0号引脚,所以用RCC开启GPIOA的时钟
LED 闪烁代码
#include "stm32f10x.h" // Device header #include "Delay.h" int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); while (1) { GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); Delay_ms(500); GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); Delay_ms(2000); } } 这里并没有什么特别的,新学了
GPIO的写函数GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);功能上感觉和GPIO_SetBits、GPIO_ResetBits没什么区别,这个函数可以通过第三个参数来决定高/低电平
LED 流水灯代码
#include "stm32f10x.h" // Device header #include "Delay.h" int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); while (1) { GPIO_Write(GPIOA, ~0x0001); // 0000 0000 0000 0001 Delay_ms(500); GPIO_Write(GPIOA, ~0x0002); // 0000 0000 0000 0010 Delay_ms(500); GPIO_Write(GPIOA, ~0x0004); // 0000 0000 0000 0100 Delay_ms(500); GPIO_Write(GPIOA, ~0x0008); // 0000 0000 0000 1000 Delay_ms(500); GPIO_Write(GPIOA, ~0x0010); // 0000 0000 0001 0000 Delay_ms(500); GPIO_Write(GPIOA, ~0x0020); // 0000 0000 0010 0000 Delay_ms(500); GPIO_Write(GPIOA, ~0x0040); // 0000 0000 0100 0000 Delay_ms(500); GPIO_Write(GPIOA, ~0x0080); // 0000 0000 1000 0000 Delay_ms(500); } }
- 这里获得了非常重要的印象:一个比特位控制一个引脚
GPIO_Write(GPIOA, ~0x0001);是GPIO的第四个写函数,它的特别之处在于通过16进制数据(第二个参数)来一次设置指定的GPIO外设的全部引脚的电平思考与体会
我现在觉得很好玩的一点是我点亮了
8个LED组成的流水灯,改动一下程序不就可以传各种信息了吗,只要有对应的协议,比如摩斯密码这种(想到了寄生虫电影里的情节,也是通过灯亮和频率来传递信息的)。所以这相当于是硬件之间通信的一种外显对吗,其实原理是差不多的所以后面要学的各种通信协议也都像这个小灯一样吗?保留这种印象学习吧
给自己准备的小练习
我们可以用这个流水灯写一个这样的小程序,来输出字符串,比如
hello world英文单词一共26个,只需要用5个流水灯来表示,后3个流水灯来指示输出的开始、结束、单词拼写的开始、结束
实现代码如下:
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 字母对应的16进制码
uint16_t letter_table[26] = {
0x0001, // a 0000 0001
0x0002, // b 0000 0010
0x0003, // c 0000 0011
0x0004, // d 0000 0100
0x0005, // e 0000 0101
0x0006, // f 0000 0110
0x0007, // g 0000 0111
0x0008, // h 0000 1000
0x0009, // i 0000 1001
0x000A, // j 0000 1010
0x000B, // k 0000 1011
0x000C, // l 0000 1100
0x000D, // m 0000 1101
0x000E, // n 0000 1110
0x000F, // o 0000 1111
0x0010, // p 0001 0000
0x0011, // q 0001 0001
0x0012, // r 0001 0010
0x0013, // s 0001 0011
0x0014, // t 0001 0100
0x0015, // u 0001 0101
0x0016, // v 0001 0110
0x0017, // w 0001 0111
0x0018, // x 0001 1000
0x0019, // y 0001 1001
0x001A // z 0001 1010
};
// 准备好要输出的字符串
char str[] = "hello world and world peace";
// 后三个灯全亮表示开始
GPIO_Write(GPIOA, ~0x00E0);
Delay_ms(2000);
// 遍历的方式用前5个LED灯逐个输出字符
for(int i = 0; str[i] != '\0'; i++)
{
char c = str[i];
// 用空格来标记单词的结束,配合尾灯特效
if(c == ' ')
{
GPIO_Write(GPIOA, ~0x0020);
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0040);
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0080);
Delay_ms(500);
}
else
{
int num = c - 'a';
uint16_t code = letter_table[num];
GPIO_Write(GPIOA, ~code);
Delay_ms(1000);
// 全暗表示一个字符输出结束
GPIO_Write(GPIOA, 0xFFFF);
Delay_ms(500);
}
}
// 后三个灯第二次全亮表示结束
GPIO_Write(GPIOA, ~0x00E0);
Delay_ms(2000);
GPIO_Write(GPIOA, 0xFFFF);
while (1)
{
}
}