一.STM32F103C8T6
(1)命名规则
Flash 存储器
Flash 存储器 是一种非易失性存储器,用于存储程序代码、常量数据(如字符串、表格等)和配置信息。即使在断电后,Flash 中的数据仍然保留。
在 STM32 中,Flash 主要用于存储用户编写的固件代码,以及一些需要在启动时加载的初始化数据。
特点
非易失性:数据在断电后不会丢失。
可编程:可以通过特定的编程接口(如 JTAG、SWD)进行擦除和编程。
读取速度快:相对于 EEPROM 等其他非易失性存储器,Flash 的读取速度更快。
擦写次数有限:Flash 的擦写次数是有限的,通常在数万到数十万次之间。因此,在频繁更新的数据存储中,应避免直接使用 Flash。
STM32 中的 Flash
容量:不同的 STM32 系列和型号,其 Flash 容量不同。例如,STM32F103C8T6 的 Flash 为 64KB,而 STM32F103RCT6 的 Flash 为 256KB。
组织结构:Flash 通常被组织为多个扇区(sector)或页(page),每个扇区或页可以单独擦除和编程。
启动模式:STM32 可以从 Flash 启动,也可以从 SRAM 启动,具体取决于启动配置。
SRAM(静态随机存取存储器)
定义与用途
SRAM 是一种易失性存储器,用于存储程序运行时的临时数据,如变量、堆栈、堆等。在断电后,SRAM 中的数据会丢失。
在 STM32 中,SRAM 主要用于存储程序运行时需要频繁访问和修改的数据。
特点
易失性:数据在断电后丢失。
读写速度快:SRAM 的读写速度非常快,适合用于需要高速数据访问的应用。
静态:不需要刷新电路,功耗较低。
容量相对较小:相对于 Flash,SRAM 的容量通常较小,成本较高。
STM32 中的 SRAM
容量:不同的 STM32 系列和型号,其 SRAM 容量不同。例如,STM32F103C8T6 的 SRAM 为 20KB,而 STM32F103RCT6 的 SRAM 为 64KB。
组织结构:SRAM 通常被组织为多个区域,如堆栈区、堆区、变量区等。
启动模式:STM32 可以从 SRAM 启动,但这需要特殊的配置和编程,通常用于调试或特定的应用场景。
Flash 和 SRAM 的比较
程序存储
Flash 用于存储用户编写的固件代码,以及一些需要在启动时加载的初始化数据。
SRAM 用于存储程序运行时需要频繁访问和修改的数据,如变量、堆栈等。
数据存储
Flash 可以用于存储需要长期保存的数据,如配置参数、日志等。但需要注意擦写次数的限制。
SRAM 不适合用于长期数据存储,因为断电后数据会丢失。
启动模式
STM32 可以配置不同的启动模式,从 Flash 或 SRAM 启动。具体配置方法可以参考 STM32 的参考手册。
优化与使用建议
Flash 编程:尽量减少对 Flash 的擦写操作,特别是在频繁更新的数据存储中。可以考虑使用 EEPROM 或外部 Flash 来存储需要频繁更新的数据。
SRAM 管理:合理管理 SRAM 的使用,避免内存泄漏和碎片化。可以使用内存管理工具或库来帮助管理内存。
缓存与缓冲:利用 SRAM 作为缓存或缓冲,提高数据访问速度。例如,可以使用 SRAM 作为 DMA 缓冲区,提高数据传输效率。
(2)系统结构
(3)引脚定义
二.新建工程模板
(1)型号分类及缩写
在 STM32 微控制器中,Flash 和 SRAM 是两个关键的存储器类型,它们在嵌入式系统的运行中扮演着不同的角色。以下是对这两个存储器的详细解释:
(2)工程建立
1)新建工程文件夹,Keil中新建工程,选择型号
2)工程文件夹中新建文件夹Start、Library、User,复制固件库文件到工程文件
(Start)内核寄存器描述:core_cm3.c/h
(Start)外设寄存器描述:stm32f10x.h
(Start)定义SystemInit:System_xx.c/h
(Start)启动调用函数描述:startup_md.s
(Library)库函数描述:misc.c/h;stm32f10x_adc.c/h;…
(User)库函数配置描述:stm32f10x——conf.h
(User)定义中断处理函数:stm32f10x_it.c/h
(User)定义main函数:main.c
3)keil工程里建分组Start、Library、User,将文件夹内的文件添加到工程分组中
4)工程选项,C/C++,Include Paths内声明所有包含头文件的文件夹
5)工程选项,C/C++Define输入USE_STDPERIPH_DIRVER
6)工程选项,Debug选择对应调试器,Setting,Flash Download勾选Reset and run
三.GPIO输出:LED和蜂鸣器
1)GPIO的8种工作模式
选择STM32的GPIO工作模式时,需要根据具体的应用场景和需求来决定。以下是一些选择工作模式时的考虑因素:
1.
输入模式:
如果你需要读取外部设备的状态,并且外部设备可以提供稳定的高或低电平信号,可以选择浮空输入。
如果外部设备可能处于高阻态或未连接状态,为了确保读取到稳定的电平,可以选择上拉输入或下拉输入。上拉输入适用于外部设备通常为低电平或未连接时,下拉输入适用于外部设备通常为高电平时。
2.
输出模式:
如果你需要控制一个LED灯或驱动一个简单的数字设备,推挽输出模式通常是最合适的选择,因为它可以提供稳定的高电平和低电平输出。
如果你需要实现如I2C总线上的多主机通信,或者需要实现一个集电极开路输出,那么开漏输出模式会更适合。(软件IIC)
3.
模拟模式:
如果你的应用需要读取模拟信号,如温度传感器的输出,那么需要将GPIO配置为模拟输入模式,并连接到ADC模块。
STM32的GPIO不支持直接的模拟输出,但可以通过DAC模块输出模拟信号。
4.
特殊模式(复用功能模式):
当你需要使用STM32的内置外设(如UART、SPI、I2C等)时,需要将相应的GPIO引脚配置为复用功能模式。根据外设的需要,可能还需要配置为复用推挽输出或复用开漏输出。(硬件IIC:复用开漏输出,SPI:复用推挽输出)
在选择GPIO工作模式时,还需要考虑以下因素:
电气特性:不同的模式下,GPIO引脚的电气特性(如输出电流能力、输入/输出电平标准等)会有所不同。
功耗:某些模式(如开漏输出)可能更适合低功耗应用。
电路设计:根据电路设计的需要,选择合适的上拉/下拉电阻值或是否需要外部上拉/下拉电阻。
最后,确保在配置GPIO之前,仔细阅读STM32的参考手册和数据手册,了解每个引脚的复用功能和电气特性,以便做出正确的选择。在实际应用中,可能还需要通过实验和调试来验证所选模式是否满足设计要求。
2.LED接线图
3.LED驱动文件封装LED.c和LED.h
头文件led.h
#ifndef __LED_H
#define __LED_H //避免重复引用
#endif
源代码led.c
1.RCC_APB2PeriphClockCmd()函数
使能端口时钟(PC)
2.GPIO_Init()函数
定义结构体,GPIO结构体成员初始化
配置输出模式(PP)
输出速率(50MHZ)
2.GPIO_SetBits()函数
初始化PC8电平(高)
LED.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
while (1)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500);
GPIO_SetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
Delay_ms(500);
}
}
四.GPIO输入:按键和传感器
1)接线图
#include "stm32f10x.h" // Device header
#include "Delay.h"
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
Delay_ms(20);
KeyNum = 1;
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
Delay_ms(20);
KeyNum = 2;
}
return KeyNum;
}
#include "Key.h"
uint8_t KeyNum;
int main(void)
{
LED_Init();
Key_Init();
while (1)
{
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
LED1_Turn();
}
if (KeyNum == 2)
{
LED2_Turn();
}
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_55389449/article/details/139620779
|