一、初识STM32

什么是STM32

stm32是意法半导体公司推出的一系列基于ARM Coretex-M内核的32位微控制器

STM32分类

按内核架构分类

Coretex_M0内核系列

Coretex_M3内核系列

Coretex_M4内核系列

Coretex_M7内核系列

按应用领域分类

通用型 如STM32F103

低功耗型

高性能型

电机控制专用型

按引脚数量和封装形式分类

小封装、少引脚系列

中等封装、中等引脚数量

大封装、多引脚系列

STM32命名方法

STM32F103VET6为例子

【家族】STM32表示32bit的MCU
【产品类型】F表示基础性
【引脚数目】V表示100pin,(C:48、R(64)、Z(144))
【Flash大小】E表示512KB(C:256、I:2048)
【封装】T表示QFP封装
【温度】6表示温度为A:-40~85℃

画原理图时的引脚分类

【电源】VBAT,VDD VSS,VDDA VSSA,VREF+ VREF-等
【晶振IO】主晶振IO,RTC晶振IO
【下载IO】用于JTAG下载的IO:JTMS\JTCK\JTDI\JTDO\NJTRST
【BOOT IO】BOOT0,BOOT1用于设置系统的启动方式
【复位IO】NRST,用于外部复位
以上5部分IO组成的系统我们也叫做最小系统

GPIO

1.专用器件接到专用的总线,比如I2C,SPI,SDIO,FSMC,DCMI这些总线的器件需要接到专用的IO
2.普通的元器件接到GPIO,比如蜂鸣器,LED,按键等元器件用普通的GPIO
如果还有剩下的IO可根据项目需要引出或者不引出

STM32的启动方式

程序下载:根据boot配置方式分为仿真器和串口下载

BOOT0:     BOOT1         启动方式
    0        X          内部FLASH启动
    1        0          系统存储器
    1        1          内部SRAM
​

寄存器

存储器映射

给存储器分配地址的过程就称为存储器映射

驱动单元:

ICode总线:专门用来取指令的
DCode总线:取数据的  const常量数据存放在Flash中,变量数据存放在SRAM中
System总线:访问外设的寄存器也叫读写寄存器
DMA总线:用来传输数据 数据可以在外设数据寄存器中:Flash、SRAM
由于DCode和DMA都要访问数据,所以这两个在取数据的时候要经过总线矩阵来仲裁

被动单元

Flash:内部的闪存存储器 写好的程序就放在这个地方 内核通过ICode总线来取里面的指令
SRAM:程序的变量、堆栈等的开销都基于内部的SRAM,内核通过DCode总线访问它
FSMC:灵活的静态的存储器控制器  用于扩展内存,但只能扩展静态内存即里面的S:static,不能是动态内存SDRAM就不能扩展
AHB-APB的桥:AHB延伸两条总线APB1和APB2,上面挂着32各种各样的特色外设如:GPIO,串口、I2C、SPI等
Block分了8块,每块512MB

Block0:Flash(512KB) 0x0000 0000  0x1FFF FFFF
Block1:SRAM(64KB)   0x2000 0000  0x3FFF FFFF
Block2:片上外设AHB,APB1,APB2 0x4000 0000 0x5FFF FFFF
APB1:0x4000 0000--0x4000 77FF
APB2:0x4001 0000--0x4001 3FFF
AHB:0x4001 8000-- 0x5003 FFFF
总线是APB2 0X4001 0000
GPIOA 0x4001 0800
GPIOB 0x4001 0c00
GPIOC 0x4001 1000
GPIOD 0x4001 1400
GPIOE 0x4001 1800
GPIOF 0x4001 1C00
GPIOG 0x4001 2000
总线是GPIOB  0x4001 0C00
GPIOB_CRL  0x4001 0C00
GPIOB_CRH  0x4001 0C04
GPIOB_IDR  0x4001 0C08
GPIOB_ODR  0x4001 0C0C
GPIOB_BSRR 0x4001 0C10
GPIOB_BRR  0x4001 0C14
GPIOB_LCKR 0x4001 0C18

寄存器映射

给已经分配好地址的、有特定功能的内存单元取别名的过程就叫寄存器映射

引脚输出高低电平

让BPIOB端口的16个引脚输出高电平

//GPIOB端口全部输出 高电平
*(unsigned int*)(0x40010C0C)=0xFFFF;
1.0x40010C0C是GPIOB输出数据寄存器ODR的地址,在《STM32F10xx参考手册》中寄存器映射中找到
2.(unsigned int*)作用是强制类型转换,转换成指针

封装成库函数/GPIO

寄存器(GPIO)结构体

使用结构体对GPIO寄存器组的封装
typedef unsigned        int uint32_t;
typedef unsigned        int uint16_t;
/*GPIO寄存器列表*/
typedef struct{
          寄存器名称     地址偏移
    uint32_t CRL;        0x00
    uint32_t CRH;        0x04
    uint32_t IDR;        0x08
    uint32_t ODR;        0x0C
    uint32_t BSRR;       0x10
    uint32_t BSR;        0x14
    uint32_t LCKR;       0x18
}GPIO_TypeDef;

总线基址与外设基址外设声明引脚定义

总线基址和外设基址
 /*外设基址*/Block2
#define PERIPH_BASE         ((unsigned int)0x4000 0000)
/*总线基址*/
#define APB1PERIPH_BASE     (PERIPH_BASE)
#define APB2PERIPH_BASE      (PERIPH_BASE+0x00010000)
#define AHBPERIPH_BASE       (PERIPH_BASE+0x00020000)
/*GPIO外设基址*/
    #define GPIOA_BASE          (APB2PERIPH_BASE+0x0800)
    #define GPIOB_BASE          (APB2PERIPH_BASE+0x0C00)
    #define GPIOC_BASE          (APB2PERIPH_BASE+0x1000)
    #define GPIOD_BASE          (APB2PERIPH_BASE+0x1400)
    #define GPIOE_BASE          (APB2PERIPH_BASE+0x1800)
    #define GPIOF_BASE          (APB2PERIPH_BASE+0x1C00)
    #define GPIOG_BASE          (APB2PERIPH_BASE+0x2000)
/*寄存器基址,以GPIOB为例*/
    #define GPIOB_CRL           GPIOB_BASE_0x00
    #define GPIOB_CRH           GPIOB_BASE_0x04
    #define GPIOB_IDR           GPIOB_BASE_0x08
    #define GPIOB_ODR           GPIOB_BASE_0x0C
    #define GPIOB_BSRR          GPIOB_BASE_0x10
    #define GPIOB_BSR           GPIOB_BASE_0x14
    #define GPIOB_LCKR          GPIOB_BASE_0x18
    #define RCC_BASE            AHBPERIPH_BASE+0x10000
  
    /*外设声明*/
     #define GPIOA        ((GPIO_TypeDef *) GPIOA_BASE)
     #define GPIOB        ((GPIO_TypeDef *) GPIOB_BASE)
     #define GPIOC        ((GPIO_TypeDef *) GPIOC_BASE)
     #define GPIOD        ((GPIO_TypeDef *) GPIOD_BASE)
     #define GPIOE        ((GPIO_TypeDef *) GPIOE_BASE)
     #define GPIOF        ((GPIO_TypeDef *) GPIOF_BASE)
     #define GPIOG        ((GPIO_TypeDef *) GPIOG_BASE)
     #define RCC          ((RCC_TypeDef *) RCC_BASE)
    /*引脚定义*/
    #define GPIO_Pin_0          ((uint16_t)0x0001)选择pin0(1<<0)
    #define GPIO_Pin_1          ((uint16_t)0x0002)选择pin1(1<<1)
    #define GPIO_Pin_2          ((uint16_t)0x0004)选择pin2(1<<2)
    #define GPIO_Pin_3          ((uint16_t)0x0008)选择pin3(1<<3)
    #define GPIO_Pin_4          ((uint16_t)0x0010)
    #define GPIO_Pin_5          ((uint16_t)0x0020)
    #define GPIO_Pin_6          ((uint16_t)0x0040)
    #define GPIO_Pin_7          ((uint16_t)0x0080)
    #define GPIO_Pin_8          ((uint16_t)0x0100)
    #define GPIO_Pin_9          ((uint16_t)0x0200)
    #define GPIO_Pin_10         ((uint16_t)0x0400)
    #define GPIO_Pin_11         ((uint16_t)0x0800)
    #define GPIO_Pin_12         ((uint16_t)0x1000)
    #define GPIO_Pin_13         ((uint16_t)0x2000)
    #define GPIO_Pin_14         ((uint16_t)0x4000)
    #define GPIO_Pin_15         ((uint16_t)0x8000)
GPIO初始化及输出
#define LED_G_GPIO_PORT              GPIOB
#define LED_G_GPIO_CLK_ENABLE        (RCC->APB2ENR |= (1)<<3)
#define LED_GREEN                   GPIO_Pin_0
    void Delay(uint32_t count)
{
    for(;count!=0;count--);
}
int main(void)
{
    GPIO InitTypeDef  GPIO_InitStructure;
    LED_G_GPIO_CLK_ENABLE;
    
    GPIO_InitStructure.GPIO_Pin = LED_GREEN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_pp;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHZ;
    GPIO_Init(LED_G_GPIO_PORT,&GPIO_InitStructure);
    while(1)
    {
        GPIO_SetBits(LED_G_GPIO_PORT,GPIO_Pin_0);
        Delay(0xFFFF);
        GPIO_ResetBits(LED_G_GPIO_PORT,GPIO_Pin_0);
        Delay(0xFFFF);
    }
}

GPIO功能框图讲解

image-20241230143506970

1.保护二极管及上、下拉电阻
引脚的两个保护二极管可以防止引脚外部过高或过低的电压输入
引脚电压高于Vdd时,上方二极管导通
引脚电压低于Vss时,下方二极管导通防止不正常电压引入芯片导致芯片烧毁
2.P-MOS管和N-MOS管
输出模式
推挽输出模式:
    输入高电平,上方P-MOS导通下方N-MOS关闭,对外输出高电平
    输入低电平,下方N-MOS导通,上方P-MOS关闭,对外输出低电平
    引脚高低电平切换时,两个MOS管都导通,P灌溉电流,N拉电流。推挽输出的    低电平0v高电平3.3v
开漏输出模式:
    P-MOS管完全不工作
    控制输出为0,低电平,P-MOS管关闭,N-MOS管导通,使输出接地
    控制输出为1,无法直接输出高电平,P-MOS和N-MOS都关闭,引脚既不输出  高电平,也不输出低电平,为高阻态。正常使用必须接上拉电阻
3.输出数据寄存器
    双MOS管电路的输入信号,是由GPIO“输出数据寄存器GPIOx_ODR”提供的
    修改输出数据寄存器的值,就能修改GPIO引脚的输出电平
4.复用功能输出
    复用是指32的其他片上外设对GPIO引脚进行控制,此时GPIO引脚算是第二用途
5.输入数据寄存器
    GPIO引脚经过内部的上、下拉电阻,可以配置成上/下拉输入,再连接到肖特基触发器,信号经过触发器后模拟信号转化为0、1的数字信号,存储在“输入数据寄存器GPIOx_IDR”中,通过读取该寄存器就可以了解GPIO引脚的电平状态
推挽输出,P-MOS管Us>Ug时导通,相等时截止,N-MOS管,Us<Ug时导通相等时截止

GPIO工作模式

模拟输入 用于ADC采集
浮空输入 接按键时使用 电平不确定,外部输入决定
下拉输入 默认的电平由上拉或下拉决定
上拉输入
开漏输出 只有N-MOS管工作
推挽输出 双MOS管轮流工作
​
控制端口高低控制寄存器CRH、CRL可以配置每个GPIO的工作模式和工作速度
CRL控制端口低8位,CRH控制端口高8位

GPIO启动文件

功能

1.初始化堆栈指针SP=_initial_sp
2.初始化PC指针=Reset_Handler
3.设置堆、栈的大小
4.初始化中断向量表
5.配置外部SRAM作为数据存储器
6.调用SystemIni()函数 配置系统时钟
7.调用C库函数_main初始化用户堆栈,从而最终调用main函数去到C的世界
启动文件startup_stm32f10x_hd.s

STM32标准库

CMSIS标准及库层次关系

CMSIS 标准就是新建了一个软件抽象层

image-20241230164151048

用户需要配置的文件
stm32f10x_it.c中断服务函数
stm32f10x_it.h中断服务函数头文件
工程内组文件夹内容清单
STARTUP:startup_stm32f10x_hd.s
CMSIS: core_cm3.c、system_stm32f10x.c
FWLB:STM32F10X_StdPeriph_Driver\src文件夹下的全部c文件即固件库
USER:用户编写的文件、main.c、stm32x_it.c中断服务函数
DOC:工程说明.txt

CMSIS标准最主要的是CMSIS核心层它包括:
    内核函数层:包含用于访问内核寄存器的名称、地址定义,主要由ARM公司提供
    设备外设访问层:提供了片上的核外外设的地址和中断定义,主要由芯片生成商提供
CMSIS:
    CoreSupport:
                core_cm3.c
                core_cm3.h
    DeviceSupport:
                startup:    
                        startup_stm32f10x_hd.s
                stm32f10x.h
                system_stm32f10x.c
                system_stm32f10x.h

位带

stm32中位操作就是通过访问位带别名区来实现单独地对一个比特位进行读和写
外设位带别名区地址:
假设某个位,记它所在字节的地址为A,位序号为n(0<=n<=7)
该位在别名区的地址为=0x42000000+(A-0x40000000)*8*4+n*4
0x42000000是外设别名区起始地址
0x40000000是外设位带区的起始地址
A-0x40000000表示该位前面有多少字节
一个字节有8位,一位膨胀后是4个字节所以x8x4
n表示该位在A地址的序号,一个位膨胀后是4个字节所以x4
SRAM位带别名区地址
假设某个位,记它所在字节的地址为A,位序号为n(0<=n<=7)
该位在别名区的地址为=0x22000000+(A-0x20000000)*8*4+n*4
解析同外设位带别名区
外设位带别名区是0x44000000,SRAM位带别名区是0x22000000
一个是4一个是2
统一公式:
//把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr,bitnum)   ((addr & 0xF0000000)+0x02000000+(addr & 0x00FFFFFF)<<5)+(bitnum<<2)
addr & 0xF0000000:区别是外设还是SRAM
 ((addr & 0xF0000000)+0x02000000=0x42000000->外设位带别名区起始地址
  ((addr & 0xF0000000)+0x02000000=0x22000000->SRAM位带别名区起始地址
  addr & 0x00FFFFFF:
                屏蔽了高三位,具体屏蔽几位和最高地址有关
                相当于减去0x20000000或0x40000000
  <<5相当于x8x4
  <<2相当于x4
GPIO位操作
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n)//输出
#define PAin(n)  BIT_ADDR(GPIOA_IDR_Addr,n)//输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n)//输出
#define PBin(n)  BIT_ADDR(GPIOB_IDR_Addr,n)//输入
单独操作GPIO的某一个IO口,n(0~16),n表示具体是哪一个IO口

RCC

时钟树

image-20241230202058713

1.HSE高速外部时钟信号
    一般是8MHZ无源晶振
    这里不分频
2.PLL时钟源:
    HSE
    HSI/2(高速内部时钟信号2分频)HSI根据温度和环境情况频率会漂移一般不作为PLL时钟来源
    这里选择HSE作为时钟源
3.PLLCLK
    时钟配置寄存器CFGR中的PLLMUL设置倍频因子
    这里设置PLL时钟9倍频,PLLCLK=8Mx9=72MHZ
4.系统时钟SYSCLK
    系统时钟来源可以是HSI、HSE、PLLCLK
    具体由CFGR的SW设置
    这里设置SYSCLK=PLLCLK=72MHZ
5.AHB总线时钟HCLK
    系统时钟SYSCLK经过AHB预分频器分频之后得到APB总线时钟-HCLK,具体预分频由CFGR的HPRE设置(1,2,4,8,16,64,128)
    这里设APB1分频,HCLK=SYSCLK=72MHZ
6.APB2总线时钟HCLK2
    APB2总线时钟HCLK2由HCLK经过高速APB2预分频器得到
    这里粗略设置为1分频,PCLK=HCLK=72MHZ
7.APB1总线时钟HCLK1
    APB1总线时钟由低速APB预分频得到
    这里设置为2分频HCLK1=HCLK/2=36MHZ
步骤:
1.使能HSE
2.等待HSE启动稳定并做超时处理
(HSE启动成功)
3.使能Flash预存取缓冲区
4.设置系统时钟与Flash的时间比例为2
5.设置AHB、APB2、APB1预分频因子(1、1、2)
6.设置PLL时钟来源和倍频因子
7.使能PLL
8.等待PLL稳定
9.选择PLL作为系统时钟来源
10.读取时钟切换状态位确保PLLCLK被作为系统时钟
void HSE_SetSysClk(uint32_t RCC_PLLMul_x){
ErrorStatus HSEStatus;
    //把RCC复位成复位值
    RCC_DeInit();
    //使能HSE
    RCC_HSEConfig(RCC_HSE_ON);
    //等待HSE启动稳定
    HSEStatus = RCC_WaitForHSEStartUp();
    if(HSEStatus == SUCCESS)
    {
        //使能预取指
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
        //设置sysclk与flash访问时间比例为2
    FLASH_SetLatency(FLASH_Latency_2);
        //设置AHB、APB1、APB2预分频
  RCC_HCLKConfig(RCC_SYSCLK_Div1);
  RCC_PCLK1Config(RCC_HCLK_Div2);
  RCC_PCLK2Config(RCC_HCLK_Div1);
        //配置PLLK = HSE * RCC_PLLMul_x
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_x);
        //使能PLL
        RCC_PLLCmd(ENABLE);
        //等待PLL稳定
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
        //选择系统时钟
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        while(RCC_GetSYSCLKSource()!=0x08){}
    }
    else
    {//启动失败这里添加处理错误的代码
    }
}

中断

异常类型

1.系统异常:8个算上Reset和HardFault就是10个
2.外部中断有60个

系统中断

image-20241230212614608

外部中断

image-20241230212638723

NVIC嵌套向量中断控制器

1.中断总开关(内核级)
2.管理着包括内核与片上所有外设的中断相关功能
3.重要文件core_cm3.h和misc.h

中断优先级

1.中断优先级寄存器NVIC_IPRX,配置外部中断优先级,IPR宽度为8bit
2.先比较抢占优先级
3.若抢占优先级相同,比较子优先级
4.若子优先级相同,比较硬件中断编号,编号越小,优先级越高
f103中只用了高4位

优先级分组

1.调用NVIC_priorityGroupConfig()实现,中断相关库函数在misc.c和.h中
2.可以分为5组:
                             抢占优先级位数    子优先级位数
            NVIC_priorityGroup_0:  0               4
            NVIC_priorityGroup_1: 1               3
            NVIC_priorityGroup_2: 2               2
            NVIC_priorityGroup_3: 3               1
            NVIC_priorityGroup_4: 4               0
            
如优先级分组为NVIC_priorityGroup_1
    抢占优先级位数为1,即0或1
    子优先级位数为3,即000、001、010、100、011、101、110、111(0~7)
void NVIC_priorityGroupConfig(uint32_t NVIC_priorityGroup)
{
//设置优先级分组
SCB->AIRCR = AIRCR_VECTKEY_MASK |NVIC_PriorityGroup;
}

中断编程

typedef struct{
uint8_t NVIC_IRQChannel;//中断源
uint8_t NVIC_IRQChannelPreemptionPriority;//抢占优先级
uint8_t NVIC_IRQChannelSubPriority;//子优先级
FunctionalState NVIC_IRQChannelCmd;//中断使能
}NVIC_InitTypedef;
中断服务函数在启动文件startup_stm32f10x_hd.s中
统一写在stm32f10x_it.c这个库中
​
中断服务函数的函数名必须与启动文件里预先设置的一样,若写错,系统就在中断向量表中找不到中断服务函数的入口,直接跳转到启动文件中预先写好的空函数,并在里面循环,实现不了中断

EXTI

1.external interrupt/event controller
外部中断/事件控制器
2.两大功能:产生中断、产生事件

image-20250102091337344

1.输入线:
    EXTI有20个中断/事件输入线EXTI0~EXTI15为GPIO引脚,每个GPIO的相同pin都连接在一起
    另外EXTI16~EXTI19:PVD输出、RTC闹钟、USB唤醒、以太网唤醒
2.边沿检测电路:
    上升沿/下降沿触发选择寄存器->控制信号触发
    
    
EXTI0可以通过AFIO外部中断配置寄存器1(AFIO_EXTICR1)的EXTI0位选择配置PA0、PB0、PC0、PD0、PE0、PF0、PG0

EXTI初始化

void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
//选择信号源(选择输入线)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
//初始化结构体
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_trigger_Rsing_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
//init调用
EXTI_Init(&EXTI_InitStructure);
}

编程要点

1.初始化要连接的GPIO
2.初始化EXTI用于产生中断/事件
3.初始化NVIC,用于处理中断
4.编写中断服务函数
5.编写main函数
1.初始化GPIO
void EXTI_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2periphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
2.初始化EXTI
void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
//选择信号源(选择输入线)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
/*//配置NVIC中断
NVIC_Configuration();*/
//初始化结构体
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_trigger_Rsing_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
//init调用
EXTI_Init(&EXTI_InitStructure);
}
3.初始化NVIC
void EXTI_NVIC_Config(void)
{
NVIC_InitTypDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//优先级分组
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
4.中断服务函数
在stm32f10x_it.c里
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
LED_G_TOGGLE;//在led.h里#define LED_G_TOGGLE  {LED_G_GPIO_PORT->ODR^=GPIO_Pin_0;}
//#define LED_G_GPIO_PORT    GPIOB
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
​
5.main函数
int main(void){
LED_GPIO_Config(void);
EXTI_GPIO_Config();
EXTI_NVIC_Config();
while(1){}
}
5.LED的GPIO初始化
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
}

Sys Tick系统定时器

image-20250102112831238

1.24位
2.只能递减
3.存在于内核,嵌套在NVIC中
4.所有的Cortex-M内核的芯片都具有这个定时器
中断一次的时间
T=VALUEload x 1/CLK
若clk=72M,VALUEload=72
T=72 x 1/72M=1/1000000s
1s=1000ms=1000000us=1000000000ns
T=1us
需要定时的时间
t中断次数
t x T
SysTick Config()库函数在FWLB中的stm32f10x_rcc.c中的core_m3.h中定义

通信

串行与并行

串行通信:
    少量数据线,一位一位地传输数据
并行通信:
    一次传输多位数据
​
特性         串行通信        并行通信
通信距离      较远            较近
抗干扰能力    较强            较弱
传输速率      较慢            较高
成本          较低           较高
全双工:同一时刻,两个设备之间可以同时收发数据
半双工:两个设备之间可以收发数据,但不能同时进行
单工:在任何时刻都只能进行一个方向的通信,即一个固定为发送设备,另一个固定为接受设备

同步与异步

同步与异步用时钟信号进行简单区分

USART–串口通信

1.串行通信方式
2.串口通信可分为TTL标准和RS-232标准
3.起始信号:由一个逻辑0的数据位表示
4.结束位:0.5,1,1.5或两个逻辑1的数据位表示
5.有效数据:在起始位后紧接着的就是有效数据,有效数据长度常被定义为5、6、7、或8位长
6.校验位:在有效数据位之后,有一个可选的数据校验位。为的是数据的抗干扰性
校验方法:
1.奇校验odd                     2.偶校验even
3.0校验space(校验位总为0)        4.1校验mark(校验位总为1)
5 无校验parity
USART:同步异步
UART:只有异步
TX:发送数据输出引脚
RX:接受数据输入引脚
SW_RX:数据接收引脚
nRTS:请求以发送,n表示低电平有效
nCTS:清除以发送,n表示低电平有效
SCLK:发送器时钟输出引脚
发送数据时:
TE:发送使能
TXE:发送寄存器为空,发送单字节的时候使用
TC:发送完成,发送多字节的时候使用
TXIE:发送完成中断使能
接收数据时:
RE:接收使能
RXNE:读数据寄存器非空
RXNEIE:发送完成中断使能
奇偶校验错误:PE
波特率:
Tx/Rx波特率=f/(16*USARTTDIV)
​

USART编程要点

USART,GPIO初始化配置
void USART_Config(void)
{
GPIO InitTypeDef GPIO_InitStructure;
USART InitTypeDef USART_InitStructure;
//打开usart和gpio的时钟
DEBUG_USART_GPIOAPBcClkCmd(RCC_APB2Periph_GPIOA,ENABLE);
DEBUG_USART_APBxClkCmd(RCC_APB2Periph_USART1,ENABLE);
​
//将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHZ;
GPIO_Init(GPIO_A,&GPIO_InitStructure);
    
//将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIO_A,&GPIO_InitStructure);  
​
//配置串口的工作参数
//波特率
USART_InitStructure.USART_BaudRate = DEBUG_BAUDRATE;
/*DEBUG_BAUDRATE被宏定义为115200*/
//数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
//停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
//校验位
USART_InitStructure.USART_Parity =USART_Parity_No;
//硬件流控制
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
//配置工作模式,收发一起
USART_InitStructure.USART_Mode =USART_Mode_Rx | USART_Mode_Tx;
//串口初始化配置
USART_Init(DEBUG_USARTx,&USART_InitStructure);
//DEBUG_USARTx宏定义是USART1
//串口中断优先级配置
    NVIC_Configuration();
//使能串口接收中断
USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE);
//使能串口
USART_Cmd(DEBUG_USARTx,ENABLE);
}

image-20250102205223185

DMA直接存储器访问

主要功能:传输数据不需要占用CPU
DMA1:有7个通道P->M,M->P,M->M
DMA2:有5个通道P->M,M->P,M->M  DMA只存在大容量互联型产品中
有多个DMA请求时,仲裁器管理响应先后顺序:
    1.软件阶段:有4个等级非常高、高、中、和低、
    2.硬件中断:编号越低优先级越高
在大容量产品和互联型产品中DMA1控制器优先级高于DMA2
源和目标地址的数据宽度必须一致:
    串口数据寄存器是8位,定义待发送数据也必须是8位
正确设置指针增量模式
传输过半、传输完成、传输错误、
传输完成两种模式:
    一次传输
    循环传输

常用存储器

易失性:    //存取速度快(内存)
     RAM:
        DRAM:  //动态
            SDRAM,DDR SDRAM,DDRII SDRAM,DDRIII SDRAM
        SRAM   //静态
非易失性:   //可长期保存数据(硬盘)
     ROM://只读存储器但可读可写
        MASK ROM  //只读
        PROM:
            OTPROM  //只能写入一次,一般写密钥或mac地址
            EPROM  //紫外线照射芯片内部擦除数据
            EEPROM //电可擦除存储器
     FLASH: //闪存,可重复擦写
          NOR FLASH  //较贵,可以字节擦除
          NAND FLASH //较便宜,必须以块擦除
     光盘
     软盘
     机械硬盘

IIC

1.两根引脚
2.SCL时钟线(同步收发)、SDA数据线(表示数据)
3.总线上的设备都有一个独立的地址
4.总线通过上拉电阻接到电源
5.三种传输模式:标准100kbps、快速模式400kbps、高速模式3.4Mbps
​
IIC协议层定义了:
通信的起始和停止信号
数据有效性、响应仲裁、时间同步和地址广播
起始和停止信号由主机产生

IIC特性及架构

1.软件模拟协议方式:
直接控制GPIO引脚电平产生通讯时序,需要CPU控制每个时刻引脚的状态
2.硬件协议:
32片上外设负责IIC通讯协议  减轻了CPU工作
philip公司

编程要点

1.配置引脚开漏模式
2.设能IIC外设时钟
3.配置IIC外设工作参数,使能IIC外设
4.编写IIC按字节收发函数
5.编写EEPROM存储内容函数
6.编写测试程序,校验程序

SPI

摩托罗拉公司
高速全双工
4根线:
1.SS/NSS/CS片选信号线
2.SCK时钟信号线,数据同步
3.MOSI主设备输出从设备输入
4.MISO主设备输入从设备输出
NSS、SCK、MOSI由主机控制产生
MISO由从机产生

作者:关关美仪

物联沃分享整理
物联沃-IOTWORD物联网 » 期末速成STM32复习

发表回复