目录
一、学习目标
1、了解stm32f103c8t6最小核心板的主要引脚接口;
2、掌握Keil 开发stm32程序的环境搭建和设置;
3、使用GPIO引脚,外接LED灯,编写程序让LED灯周期性亮灭。
二、STM32F103C8T6最小核心板
2.1、STM32F103C8T6简介
STM32F103C8T6 是一款基于ARM Cortex-M3内核的32位微控制器,由STMicroelectronics(ST)公司生产。它是STMicroelectronics的STM32系列微控制器中的一员,被广泛应用于嵌入式系统和电子设备中。
封装:
STM32F103C8T6 的主要引脚接口如下:
1)电源引脚:VDD: 电源正极; VSS: 电源地。
2)时钟引脚:OSC_IN: 晶振输入; OSC_OUT: 晶振输出。
3)复位引脚:NRST: 复位输入。
4)模拟引脚:PA0 至 PA7: 模拟引脚0至7,可用作ADC输入或DAC输出。
5)通用I/O引脚:PAx, PBx, PCx, PDx (x = 0 to 15): 大多数GPIO引脚都可以配置为输入、输出或具有多种功能的复用引脚。
6)其他特殊功能引脚:BOOT0: 启动模式选择; JTMS/SWDIO: JTAG/SWD数据输入/输出;JTCK/SWCLK: JTAG/SWD时钟; JTDI: JTAG数据输入; JTDO/TRACESWO: JTAG数据输出/跟踪串行输出。
2.2、STM32F103C8T6电路原理
上图是某一型号 STM32F103C8T6 的电路原理图。
复位电路:
复位电路的作用就是,板子上电的瞬间给单片机复位引脚(NRST)一个短暂的低电平,让单片机程序复位,把除了备份区域寄存器以外所有寄存器状态恢复原始状态。简单来说就是让程序重头开始跑。
系统时钟:
系统时钟一般是加外部晶振电路,相当于给单片机一个心跳。这个心跳也是一个时机基准,为单片机系统时钟、定时器之类的提供时间的基准。我们最终计算定时器的时间,都跟这个晶振息息相关。
烧录口:
烧录口的作用就是给单片机烧录程序,注入灵魂。
三、STM32F103C8T6 实现流水灯
以 STM32最小系统核心板(STM32F103C8T6)+面包板+3只(或更多)红绿蓝LED 搭建电路,使用GPIOA、GPIOB、GPIOC这3个端口控制LED灯,轮流闪烁,间隔时长1秒。
3.1、设计思路
3.1.1、STM32 创建项目(keil)
环境搭建和创建项目可参考以下博客:
stm32通过寄存器方式利用GPIO端口点亮LED_mdk配置stlink-CSDN博客
完整代码:
#define GPIOA_BASE 0x40010800
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
void SystemInit(void);
void Delay_ms(volatile unsigned int);
void A_LED_LIGHT(void);
void B_LED_LIGHT(void);
void C_LED_LIGHT(void);
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
void A_LED_LIGHT(){
GPIOA_ODR=0x0<<4; //PA4低电平
Delay_ms(1000);
GPIOA_ODR=0x1<<4; //PA4高电平
}
void B_LED_LIGHT(){
GPIOB_ODR=0x0<<9; //PB9低电平
Delay_ms(1000);
GPIOB_ODR=0x1<<9; //PB9高电平
}
void C_LED_LIGHT(){
GPIOC_ODR=0x0<<15; //PC15低电平
Delay_ms(1000);
GPIOC_ODR=0x1<<15; //PC15高电平
}
int main(){
int j=100;
// 开启时钟
RCC_APB2ENR |= (1<<2); // 开启 GPIOA 时钟
RCC_APB2ENR |= (1<<3); // 开启 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 开启 GPIOC 时钟
// 设置 GPIO 为推挽输出
GPIOA_CRL &= 0xfff0ffff; //设置位清零
GPIOA_CRL|=0x00020000; //PA4推挽输出
GPIOB_CRH&= 0xffffff0f; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出
GPIOC_CRH &= 0x0fffffff; //设置位 清零
GPIOC_CRH|=0x20000000; //PC15推挽输出
// 3个LED初始化为不亮(即高点位)
GPIOA_ODR |= (1<<4);
GPIOB_ODR |= (1<<9);
GPIOC_ODR |= (1<<15);
while(j){
A_LED_LIGHT();
B_LED_LIGHT();
C_LED_LIGHT();
}
}
void SystemInit(){
}
3.1.2、电路原理图与仿真(Proteus)
电路原理图如下:
仿真:
3.2、GPIO端口的各寄存器地址和详细参数
3.2.1、寄存器
STM32F103C8T6微控制器的寄存器是存储单元,用于控制和配置芯片的各种功能。这些寄存器包括状态寄存器、控制寄存器、数据寄存器等,分别用于指示设备状态、配置设备行为、以及读取或写入数据。通过操作这些寄存器,可以实现对外设的精确控制,如GPIO端口、ADC、DAC、USART、SPI、I2C、定时器等。
3.2.2、GPIO端口初始化设置
(1)打开时钟
GPIO 是通用输入输出端口的简称,也就是STM32 可控制的引脚, STM32 芯片的 GPIO
引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。 所有的 GPIO 引脚都有基本的输入输出功能。
GPIO的地址:
时钟的地址:
即0x40021018,则打开三个IO口的时钟需要将三个位都置1:
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
// 打开时钟
RCC_APB2ENR |= (1<<3); // 打开 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 打开 GPIOC 时钟
RCC_APB2ENR |= (1<<2); // 打开 GPIOA 时钟
(2)GPIO初始化
GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚,如型号为 STM32F103VET6 型号的芯片有 GPIOA、GPIOB、GPIOC 至 GPIOE 共 5 组 GPIO,芯片一共 100 个引脚,其中 GPIO就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能。
GPIO有8种工作模式,可大致分为三类:
(1)输入模式(模拟/浮空/上拉/下拉)
在输入模式时,施密特触发器打开,输出被禁止,可通过输入数据寄存器 GPIOx_IDR读取 I/O 状态。其中输入模式,可设置为上拉、下拉、浮空和模拟输入四种。上拉和下拉输入很好理解,默认的电平由上拉或者下拉决定。浮空输入的电平是不确定的,完全由外部的输入决定,一般接按键的时候用的是这个模式。
(2)输出模式(推挽/开漏)
在输出模式中,推挽模式时双 MOS 管以轮流方式工作,输出数据寄存器 GPIOx_ODR可控制 I/O 输出高低电平。开漏模式时,只有 N-MOS 管工作,输出数据寄存器可控制 I/O输出高阻态或低电平。输出速度可配置,有2MHz\10MHz\50MHz 的选项。此处的输出速度即 I/O 支持的高低电平状态最高切换频率,支持的频率越高,功耗越大,如果功耗要求不严格,把速度设置成最大即可。
(3)复用功能(推挽/开漏)
复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取 I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号。
通过对 GPIO 寄存器写入不同的参数,就可以改变 GPIO 的工作模式。
GPIOB的B9、GPIOC的C15、GPIOA的A4 设置如下:
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
GPIOB_CRH&= 0xffffff0f;
GPIOB_CRH|=0x00000020;
GPIOC_CRH &= 0x0fffffff;
GPIOC_CRH|=0x30000000;
GPIOA_CRL &= 0xfff0ffff;
GPIOA_CRL|=0x00010000;
3.3、探究
STM32最小系统核心板子出厂时已经焊接好了1个led灯(标注了PC13处),一般可通过此灯的点亮让编程者验证自己烧录的代码是否正常运行了。查阅最小版电路原理图和相关资料,将这个灯也用在流水灯中,重编新程序。
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
void SystemInit(void);
void Delay_ms(volatile unsigned int);
void A_LED_LIGHT(void);
void B_LED_LIGHT(void);
void C_LED_LIGHT(void);
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
void A_LED_LIGHT(){
GPIOA_ODR=0x0<<4; //PA4低电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x1<<13; //PC13高电平
}
void B_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x0<<9; //PB9低电平
GPIOC_ODR=0x1<<13; //PC13高电平
}
void C_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x0<<13; //PC13低电平
}
int main(){
int j=100;
// 开启时钟
RCC_APB2ENR |= (1<<3); // 开启 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 开启 GPIOC 时钟
RCC_APB2ENR |= (1<<2); // 开启 GPIOA 时钟
// 设置 GPIO 为推挽输出
GPIOB_CRH&= 0xffffff0f; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出
GPIOC_CRH &= 0xff0fffff; //设置位 清零
GPIOC_CRH|=0x00300000; //PC15推挽输出
GPIOA_CRL &= 0xfff0ffff; //设置位 清零
GPIOA_CRL|=0x00010000; //PA4推挽输出
// 3个LED初始化为不亮(即高点位)
GPIOB_ODR |= (1<<9);
GPIOC_ODR |= (1<<13);
GPIOA_ODR |= (1<<4);
while(j){
B_LED_LIGHT();
Delay_ms(2000);//单片机上2000 100
C_LED_LIGHT();
Delay_ms(3000);//单片机上3000 200
A_LED_LIGHT();
Delay_ms(3000);//单片机上3000 200
}
}
void SystemInit(){
}
四、总结
本次学习我们首先了解了 stm32f103c8t6最小核心板的主要引脚接口;其次结合之前的学习经历,继续学习并掌握Keil 开发stm32程序的环境搭建和设置;最后以 STM32最小系统核心板为主制作了流水灯。此次学习对我本人来说还是有一定的难度,环境搭建、软件配置还有烧录等过程都花费了很长时间。