stm32学习笔记

 路径细节

#include "./LED/bsp_led.h"  ./表示当前路径   ../表示上一层路径

#include "bsp_led.h"  需要在魔术棒里添加路径

stm32学习笔记_第1张图片

按键初始化 模式是输入

void key_config(){
    //初始化GPIO按键
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;可以不用
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;可不用
    GPIO_Init(GPIOE,&GPIO_InitStruct);
    
}

按键检测:

stm32学习笔记_第2张图片

#define KEY_ON 0

#define KEY_OFF 1

uint8_t KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

{

        if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==KEY_ON)

        {

                while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==KEY_ON);//手松开跳出

                return KEY_ON;

        }

        else

        {

                return KEY_OFF;

        }

}

主程序:

while(1)
    {
        if(KEY_Scan(GPIOE,GPIO_Pin_2)==KEY_ON)
        {
            GPIO_ToggleBits(GPIOF,GPIO_Pin_9);
        }
    }

位操作原理:(像指针)

把每个比特膨胀为一个32位的字(地址),当访问这些字的时候就可以达到访问比特的目的。

改变地址的值1或0就是位的值

stm32学习笔记_第3张图片

位带跑马灯:

        while(1)
    {
        PFout(9)=1;
        PFout(10)=1;
        delay_ms(500);
        PFout(9)=0;
        PFout(10)=0;
        delay_ms(500);
    }

启动文件

Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

执行完时,已经执行了SystemInit和main 函数,先执行SystemInit

蜂鸣器

stm32学习笔记_第4张图片

注意下拉,默认是低电平

void BEEP_Config()
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,  ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//输出
    GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//推挽
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉,默认是0   
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_Init(GPIOF,&GPIO_InitStruct);
}

while(1)
    {
        PFout(9)=1;
        PFout(8)=1;
        delay_ms(500);
        PFout(9)=0;
        PFout(8)=0;
        delay_ms(500);
    }

按键输入

stm32学习笔记_第5张图片

KEY0 上拉输入

KEY1 上拉输入

KEY2  上拉输入

上拉输入默认电平是1

读取输入的三种方法:

按键按下一次有效,一直按则无效

stm32学习笔记_第6张图片

注意:static关键字

int getValue(void)                                                int getValue(void)

{                                                                          {

        int flag=0;                                                           static int flag=0;

        flag++;                                                                flag++;

        return flag;                                                          return flag;

}                                                                           }

 static 值一直保存在存储区,一直存在

int flag=0;   每次调用都会是1

static int flag=0; 每次调用都会是1,2,3,4,5,6  相当于flag+1

按键扫描支持连续型

u8 KEY_Scan(void)

{

        if(KEY 按下)

        {

                delay_ms(10);   //延迟10-20ms,防抖

                if(KEY 确实按下)

                {

                        return KEY_Vaule;

                }

         return 无效值;

        }

}

按键扫描不支持连续性

u8 KEY_Scan(void)

{就是说key_up必须为1才能进行循环,必须是松开的时候才能进入if

        static u8 key_up=1;  //松开没按是1,按下是0 

        if( key_up&&KEY 按下) //前一次松开且按下 

        {

                delay_ms(10);   //延迟10-20ms,防抖

                key_up=0;

                if(KEY 确实按下)

                {

                        return KEY_Vaule;

                }

        }else if(KEY没有被按下) key_up=1;

}

按键扫描(两种模式合二为一)

u8 KEY_Scan(u8 mode)

{

        static u8 key_up=1;

        if(mode==1) key_up=1;//支持连按

        if(key_up &&KEY按下)

        {

                delay_ms(10);

                key_up=0;

                if(KEY 确定按下)

                {

                        return KEY_Value;

                }

        }else if(KEY没有被按下) key_up=1;

        return 没有按下;

}

如果mode==1,划掉无用的

stm32学习笔记_第7张图片

如果mode==0,划掉无用的

stm32学习笔记_第8张图片

C语言复习

位操作:6种位操作运算符

&          0 1 ~~> 0

左移<< 10101010 ~>01010100    移动补0

右移>>10101010 ~>01010101

stm32学习笔记_第9张图片

stm32学习笔记_第10张图片

#ifndef _LED_H

#define _LED_H

#endif

stm32学习笔记_第11张图片

extern表示其他文件已经定义,到其他文件中找

stm32学习笔记_第12张图片

stm32学习笔记_第13张图片

如:typedef uint8_t u8;

stm32学习笔记_第14张图片

stm32学习笔记_第15张图片

结构体作用:

同一个类型可以用数组,不同类型可以用结构体组织

stm32学习笔记_第16张图片

stm32学习笔记_第17张图片

#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)  强制转换成GPIO_TypeDef指针
GPIO 指向GPIOA_BASE的地址,GPIO里面有struct 结构体(MODER,OTYPER也存在)

stm32学习笔记_第18张图片

stm32学习笔记_第19张图片

 ​​​​stm32学习笔记_第20张图片

stm32学习笔记_第21张图片

注:PLL是锁相环,用来分频和倍频的

系统时钟System clock 大多数来源于PLLCLK,因为PLLCLK可以到168MHz

一.STM32有5个时钟源:HSI,HSE,LSI,LSE,PLL

1.HSI是高速内部时钟,RC振荡器,频率为16MHz,精度不高.可以直接作为系统时钟或者用作PLL时钟输入

2.HSE是高速外部时钟,可接振荡器,或者外接外部时钟,频率范围为4MHz~26N=MHz

正点原子板子是8M

3.LSI是低速内部时钟,RC振荡器,频率为32kHz,提供低功耗时钟,主要供应独立看门狗和自动唤醒单元使用

4.LSE是低速外部时钟,接频率为32.768MHz的石英晶体

5.PLL为锁相环倍频输出,STM32F4有两个PLL:

        主PLL由HSE或者HSI提供时钟,并具有两个不同的输出时钟

                第一个输出PLLP用于生成高速的系统时钟(最高168MHz)

                第二个输出PLLQ用于生成USB SDIO时钟

二.系统时钟SYSCLK可来源于三个时钟源

        1.HSI振荡器时钟

        2.HSE振荡器时钟

        3.PLL时钟

任何外设在使用时,必须首先使能其相应的时钟

stm32学习笔记_第22张图片

stm32学习笔记_第23张图片

SystemInit()配置过程

stm32学习笔记_第24张图片

Systick定时器

是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器
Systick定时器常用来延时,或者实时系统的时钟,这样可以节省MCU资源,不浪费一个定时器
是系统滴答定时器,一个24位的倒计数定时器,计到0时,将从RELOAD寄存器中自动重装载定时初值,只要不把它在SysTick控制及状态寄存器中的使能位清除,即使在睡眠模式也能工作

4个Systick寄存器

CTRL        SysTick控制和状态寄存器

LOAD        SysTick自动重装载寄存器

VAL            SysTick当前值寄存器

CALIB        SysTick校准寄存器

stm32学习笔记_第25张图片

stm32学习笔记_第26张图片

1 Mhz=1微秒

注:要1ms,则168/168MHz *1000

stm32学习笔记_第27张图片

 stm32学习笔记_第28张图片

调试

stm32学习笔记_第29张图片

IO引脚复用和映射

NVIC:嵌套向量中断控制器,属于内核外设,管理着包括内核和片上所有外设的中断相干功能

两个重要的库文件:core_cm4.h 和misc.c

stm32学习笔记_第30张图片

stm32学习笔记_第31张图片

数字越低,优先级越高stm32学习笔记_第32张图片
先比较主优先级,再比较子优先级,最后确定80多个优先级

中断编程的顺序

1.使能中断请求

2.配置中断优先级分组

3.配置NVIC寄存器,初始化NVIC_InitTypeDef;

4,编写中断服务函数

typedef struct
{
  uint8_t NVIC_IRQChannel;                                        中断源

  uint8_t NVIC_IRQChannelPreemptionPriority;           抢占优先级

  uint8_t NVIC_IRQChannelSubPriority;                        子优先级

  FunctionalState NVIC_IRQChannelCmd;                   使能
} NVIC_InitTypeDef;

编写中断服务函数

1-中断服务函数名要怎么写?写错了怎么办?

        必须跟中断向量表(vectors)一样,文件在startup_stm32f40xx.s启动文件中

        写错函数则执行不了,只会执行startup_stm32f40xx,s启动文件弱定义

2-中断服务函数要写在什么地方?

        stm32f4xx_it.c 因为启动文件中是弱定义,写了就不会在startup_stm32f40xx.s执行

 外部中断/事件控制器

电平变化产生中断
事件是方波产生中断

stm32学习笔记_第33张图片

输入线:

1.输入线总共有多少,具体是哪一些?

stm32学习笔记_第34张图片

2.通过配置哪个寄存器来选择?

        外部中断配置寄存器

 stm32学习笔记_第35张图片

中断服务函数列表

EXTI0_IRQHandler

EXTI1_IRQHandler

EXTI2_IRQHandler

EXTI3_IRQHandler

EXTI4_IRQHandler

EXTI9-5_IRQHandler

EXTI15-10_IRQHan dler

外部中断一般步骤:

1.使能SYSCFG时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);

2.初始化IO口为输入

GPIO_Init();

3.设置IO口与中断线的映射关系

void SYSCFG_EXTILineConfig():

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);//PE2 连接到中短线2
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);//PE3 连接到中短线3
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);//PE4 连接到中短线4

4.初始化线上中断,设置触发条件

EXTI_Init();

5.配置中断分组(NVIC),并使能中断

NVIC_Init();

6.编写中断服务函数

EXTIx_IRQHandler();

7.清除中断标志位

EXTI_ClearITPendingBit();

void EXTIX_Init(void)
{
	//1.使能SYSCFG时钟
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	

	//2.初始化IO口为输入
	KEY_Config();//按键对应的IO口初始化


	//3.设置IO口与中断线的映射关系
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,  EXTI_PinSource4);
	//4.初始化线上中断,设置触发条件
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line=EXTI_Line4;
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//中断事件
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;//默认上拉,用下降沿
	EXTI_Init(&EXTI_InitStruct);

	//5.配置中断分组(NVIC),并使能中断
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct);


	//6.编写中断服务函数


	//7.清除中断标志位	
}

void EXTI4_IRQHandler(void)
{
	delay_ms(20);//消抖
	if(KEY0==0)
	{
		LED0=!LED0;	
		LED1=!LED1;	
	}
	EXTI_ClearITPendingBit(EXTI_Line4);//清除LINE4上的中断标志位  
}

#include "exit.h"
#include "key.h"
#include "delay.h"
#include "bsp_led.h"
#include "beep.h"

6.编写中断服务函数
//外部中断2服务程序
void EXTI2_IRQHandler(void)
{    
    delay_ms(10);
    if(KEY2==0)
    {
        LED1=!LED1;
        LED0=!LED0;
    }

   7.清除中断标志位
    EXTI_ClearITPendingBit(EXTI_Line2);//清除LINE2上的中断标志位 
}       
//外部中断3服务程序
void EXTI3_IRQHandler(void)
{
    delay_ms(10);//消抖
    if(KEY1==0)
    {
        
        LED1=!LED1;
    }
    EXTI_ClearITPendingBit(EXTI_Line3);//清除LINE3上的中断标志位 
}
//外部中断4服务程序
void EXTI4_IRQHandler(void)
{
    delay_ms(10);//消抖
    if(KEY0==0)
    {
        BEEP=!BEEP;
    }
    EXTI_ClearITPendingBit(EXTI_Line4);//清除LINE4上的中断标志位 
}
//按键对应的IO口初始化         
void GPIO_KEY_Config(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOE,&GPIO_InitStruct);
}
//外部中断初始化程序
//初始化PE2~4,PA0为中断输入.
void EXTIX_Init(void)
{

    1.使能SYSCFG时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//使能SYSCFG时钟
    2.初始化IO口为输入
    GPIO_KEY_Config();//按键对应的IO口初始化


    3.设置IO口与中断线的映射关系
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2); //PE2 连接到中断线2
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3); //PE3 连接到中断线3
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4); //PE4 连接到中断线4


    4.初始化线上中断,设置触发条件
    /* 配置EXTI_Line2,3,4 */
    EXTI_InitTypeDef EXTI_InitStruct;
    EXTI_InitStruct.EXTI_Line=EXTI_Line2|EXTI_Line3|EXTI_Line4;
    EXTI_InitStruct.EXTI_LineCmd=ENABLE;//中断线使能
    EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//中断事件
    EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
    EXTI_Init(&EXTI_InitStruct);//注:每一个都需要被配置


    5.配置中断分组(NVIC),并使能中断
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel=EXTI2_IRQn;//外部中断2
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=0x01; //子优先级1
    NVIC_Init(&NVIC_InitStruct);//注:每一个都需要被配置

    NVIC_InitStruct.NVIC_IRQChannel=EXTI3_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x02;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=0x01;
    NVIC_Init(&NVIC_InitStruct);//注:每一个都需要被配置
    
    NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x03;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=0x01;
    NVIC_Init(&NVIC_InitStruct);//注:每一个都需要被配置
    
}

                                                

串口通信

USART和SPI都是全双工

stm32学习笔记_第36张图片

stm32学习笔记_第37张图片

stm32学习笔记_第38张图片

stm32学习笔记_第39张图片

stm32学习笔记_第40张图片

stm32学习笔记_第41张图片

HAL库的中断

void exti_init(void)
{
    //GPIO使能 
    GPIO_InitTypeDef GPIO_Init;
    __HAL_RCC_GPIOE_CLK_ENABLE();
    GPIO_Init.Mode=GPIO_MODE_IT_FALLING; //下降沿中断
    GPIO_Init.Pin=GPIO_PIN_2;
    GPIO_Init.Pull=GPIO_PULLUP;
    
    HAL_GPIO_Init(GPIOE,&GPIO_Init);
    
    //NVIC中断
    HAL_NVIC_SetPriority(EXTI2_IRQn,2 ,2 );
    HAL_NVIC_EnableIRQ(EXTI2_IRQn);

}

void EXTI2_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);//公共处理函数:清楚中断并跳转HAL_GPIO_EXTI_Callback
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{    
    delay_ms(10);
    if(KEY2==0)
    {
        HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9);
    }

}
 

你可能感兴趣的:(stm32,学习,笔记)