STM32学习

初识工程文件目录层次

Project
USER
uvprojx工程文件
源文件
头文件
main
system_stm32f10x
stm32f10x_it
stm32f10x
stm32f10x_conf
HARDWARE
片上外设,每个片上外设都有单独的文件夹包含头文件和源文件
CORE
包含启动文件和core文件:头文件和源文件
STM32F10x_FWLib
Firmware固件库,包含src-source源文件,inc头文件
TXT
包含readme文件
APP
用到的硬件,和固件库类似
SYSTEM
delay函数printf函数sys函数usart函数
OBJ
中间文件和hex文件
keilkill

在这里插入图片描述

stm32f10x_it.c、stm32f10x_it.h和stm32f10x_conf.h文件作用: 链接

  1. system_stm32f10x:
    包含了STM32 芯片上电后初始化系统时钟、扩展外部存储器用的函数
  2. stm32f10x头文件:片上外设固件库头文件

初始化GPIO

如何使用结构体控制寄存器:
GPIO_Init函数中左边的GPIOC为GPIO_TypeDef类型的指针(地址)变量
GPIO_Init函数中右边的结构体变量是自定义的,成员变量也是库函数中给定的(自己选择合适参数)赋值
通过GPIO_Init函数使寄存器相关的结构体通过自定义的结构体完成初始化

GPIO_Init(GPIOC, &GPIO_InitStructure);
typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;

使用#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) 将该结构体首地址赋值为寄存器位置

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)

初识库函数

初始化GPIO

步骤:

  1. 声明GPIO_InitTypeDef类型的结构体
  2. 初始化结构体变量,赋值
  3. 开启RCC_APB2PeriphClockCmd时钟
  4. 将结构体变量传入GPIO_Init函数
void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;//定义一个GPIO_InitTypeDef类型的结构体
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//开启GPIO端口时钟
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13; //PC13
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//通用推挽输出
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//引脚速率50MHZ
	
	GPIO_Init(GPIOC, &GPIO_InitStructure);
}
typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

注意结构体中成员变量类型

  1. GPIO_Pin类型是uint16_t
    在stm32f10x_gpio.h头文件中使用#define来定义的
    #define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected /
    #define GPIO_Pin_1 ((uint16_t)0x0002) /
    !< Pin 1 selected */
    ……

  2. GPIO_Speed类似是GPIOSpeed_TypeDef(枚举类型)
    所以变量值只能在枚举成员中选择

typedef enum
{ 
GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14,
GPIO_Mode_Out_PP = 0x10,
GPIO_Mode_AF_OD = 0x1C,
GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

Keil软件

在这里插入图片描述

STM32F10X_MD,USE_STDPERIPH_DRIVER
stm32f10x.h中使用了条件编译

#ifdef USE_STDPERIPH_DRIVER
#include "stm32f10x_conf.h"
#endif
#ifdef STM32F10X_MD
  ADC1_2_IRQn                 = 18,     /*!< ADC1 and ADC2 global Interrupt                       */
  USB_HP_CAN1_TX_IRQn         = 19,     /*!< USB Device High Priority or CAN1 TX Interrupts       */
  USB_LP_CAN1_RX0_IRQn        = 20,     /*!< USB Device Low Priority or CAN1 RX0 Interrupts       */
  CAN1_RX1_IRQn               = 21,     /*!< CAN1 RX1 Interrupt                                   */
  CAN1_SCE_IRQn               = 22,     /*!< CAN1 SCE Interrupt                                   */
  EXTI9_5_IRQn                = 23,     /*!< External Line[9:5] Interrupts                        */
  TIM1_BRK_IRQn               = 24,     /*!< TIM1 Break Interrupt                                 */
  TIM1_UP_IRQn                = 25,     /*!< TIM1 Update Interrupt                                */
  TIM1_TRG_COM_IRQn           = 26,     /*!< TIM1 Trigger and Commutation Interrupt               */
  TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                       */
  TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt                                */
  TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt                                */
  TIM4_IRQn                   = 30,     /*!< TIM4 global Interrupt                                */
  I2C1_EV_IRQn                = 31,     /*!< I2C1 Event Interrupt                                 */
  I2C1_ER_IRQn                = 32,     /*!< I2C1 Error Interrupt                                 */
  I2C2_EV_IRQn                = 33,     /*!< I2C2 Event Interrupt                                 */
  I2C2_ER_IRQn                = 34,     /*!< I2C2 Error Interrupt                                 */
  SPI1_IRQn                   = 35,     /*!< SPI1 global Interrupt                                */
  SPI2_IRQn                   = 36,     /*!< SPI2 global Interrupt                                */
  USART1_IRQn                 = 37,     /*!< USART1 global Interrupt                              */
  USART2_IRQn                 = 38,     /*!< USART2 global Interrupt                              */
  USART3_IRQn                 = 39,     /*!< USART3 global Interrupt                              */
  EXTI15_10_IRQn              = 40,     /*!< External Line[15:10] Interrupts                      */
  RTCAlarm_IRQn               = 41,     /*!< RTC Alarm through EXTI Line Interrupt                */
  USBWakeUp_IRQn              = 42      /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */  
#endif /* STM32F10X_MD */  

容量大小选择

在这里插入图片描述

断言函数

definition 定义
reference 引用
@arg:argument自变量
@param:parameter参数
填入的自变量可以通过”“运算符组合使用(”|“)

assert_param:断言函数,判断所填入的参数是否合法

GPIO_Init(GPIOC, &GPIO_InitStructure);
/**
  * @brief  Initializes the GPIOx peripheral according to the specified
  *         parameters in the GPIO_InitStruct.
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
  *         contains the configuration information for the specified GPIO peripheral.
  * @retval None
  */
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  

使用库函数操作硬件

USART

串口:链接
串口简介:通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备, 可以灵活地与外部设备进行全双工数据交换。 有别于USART还有一个UART(Universal Asynchronous Receiver and Transmitter), 它是在USART基础上裁剪掉了同步通信功能,只有异步通信。 简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是UART。

串口使用步骤:
1.串口时钟,GPIO时钟使能
2.GPIO端口模式设置
3.串口参数初始化
4.开启中断并且初始化NVIC(在接受串口数据时使用)
5.使能串口
6.编写中断处理函数

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//1.串口时钟,GPIO时钟使能

GPIO_Init(GPIOA, &GPIO_InitStructure);// 2.GPIO端口模式设置

USART_Init(USART1, &USART_InitStructure);//3.串口参数初始化

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_Init(&NVIC_InitStructure);// 4.开启中断并且初始化NVIC(在接受串口数据时使用)

USART_Cmd(USART1, ENABLE);//5.使能串口

void USART1_IRQHandler(void)// 6.编写中断处理函数

串口传输状态相关函数:

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

关于TXE标志位(Transmit Exchange Empty),TC(Transmission Complete)RXNE(Receive Exchange Not Empty)
在这里插入图片描述
TXE为1:TDR里面的数据全部移到了移位寄存器,且没有新的数据进入TDR
TXE为0:TDR里面有数据。
TC为1:从TDR发过来的数据全部移送到TX引脚,且TDR里也没有新的数据
TC为0:从TDR里过来的数据还没有全部移过来,或者之前TDR里的数据被移走了,但TDR里又来了新的数据

时钟

HSE、HSI、LSE、LSI:内外部,高低速时钟
S(Speed)、H(High)、L(Low)、E(External)
PLL的意思是Phase-locked Loop,中⽂意思即为锁相环
STM32时钟讲解:链接

系统时钟配置:

  1. 在startup_stm32f10x md.s文件中找到要运行的SystemInit函数
    在这里插入图片描述
  2. 跳转到了system_stm32f10x.c文件中
    在这里插入图片描述
    3.同system_stm32f10x.c文件中设置系统时钟,是条件编译
    在这里插入图片描述
    在这里定义的宏
    在这里插入图片描述

使用SYSTICK滴答定时器

使用SYSTICK滴答定时器编写延时函数

void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);

中断

NVIC是内核外设
core_cm3.h和stm32f10x.h头文件区别
misc.h
STM32最多有256种中断,每个产品不全部拥有所有中断,优先级概念和C51不同,然后对优先级分组:用4bit(16种)抢占优先级>响应优先级
在这里插入图片描述
每个工程为NVIC设置一次分组即可

软硬件调试

Keil仿真

开始配置

在这里插入图片描述

其中软件仿真在Target->XTal下配置时钟,硬件在Setting下配置
在这里插入图片描述
通过数据库中芯片描述来填写软件仿真参数
在这里插入图片描述

开始仿真

  1. 进入软件仿真
    在这里插入图片描述
  2. 添加断点
  3. 全速运行到第一个断点位置
    在这里插入图片描述

查看GPIO的状态

查看GPIO寄存器状态

在这里插入图片描述

查看参数波形 (硬件仿真中不支持)

在这里插入图片描述

设置一些参数

位带操作

STM32单片机不支持单个位操作
Bit-banding简称位带,有人也叫位段。支持位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。
1Bit膨胀到32Bit(4字节)
位带操作:链接

1.SRAM区的最低1MB(0x2000 0000 — 0x200F FFFF) 映射到(0x2200 0000 — 0x23FF FFFF)。
2.片内外设区的最低1MB(0x4000 0000 — 0x400F FFFF)映射到(0x4200 0000 — 0x43FF FFFF)。

1字 = 4字节
1字节 = 8bit

I2C

PID

一种闭环控制算法(程序)
开环:输入不受输出的影响
PID在线模拟网站
PID讲解
博客园讲解
连续PID:
在这里插入图片描述
离散化:
在这里插入图片描述

P项: Kp∗ek
误差越大,P的输出越大
P的作用是减小测量值和理论值之间的误差,让测量值不断接近理论值

D项: Kd(ek-ek-1
两次误差值相差越大,输出的值越大
D的作用是“阻尼”如果系统的误差很大,或者P参数设置的很大,那么P的输出就会很大,导致系统剧烈相应,出现过冲现象,此时就用D来抑制,让系统刚好可以停在理论值而不过程。

I项: K i ∑ j = 1 k e j Ki\sum_{j= 1}^{k}e_j Kij=1kej
只要存在误差(这种误差叫稳态误差),不论误差有多小,i的输出也会不断的累积,越来越大.
I的作用是消除稳态误差,当系统误差已经接近0时,P的输出会很小,起不到继续减小误差的作用,导致误差始终没办法减小到0,这时用到I项,让误差不断累加,并将累加的值输出.
I项常用于追求更精准的控制.

程序积累

EC11消抖:链接
在这里插入图片描述
A脚设置为上升下降沿均会进中断,下降上升一个变换周期,判断这个周期的A脚,B脚的始末状态,来判断正反转一次。

#define Aio PA3
#define Bio PA4
int flag = 0;  //标志位,默认是0,且在中断中和a相是否低电平 相与操作
boolean CW_1 = 0;
boolean CW_2 = 0;
//只看中断代码即可
void Aio_inter() 
{
  // 只要处理一个脚的外部中断--上升沿&下降沿
  int alv = digitalRead(Aio);
  int blv = digitalRead(Bio);
  if (flag == 0 && alv == LOW) //flag默认是0,a相下降沿时,读取b相点平,且标志位置1
  {
    CW_1 = blv;
    flag = 1;
  }//执行完毕,不会进入另一个if判断
  if (flag && alv)//EC11继续拧,又进入中断,在a相上升沿时(一个周期了)
  {
    CW_2 = !blv;  //取反是因为 alv,blv必然异步,一高一低。
    if (CW_1 && CW_2) {
      dir++;
    }
    if (CW_1 == false && CW_2 == false) {
      dir--;
    }
    flag = 0;
  }
}//以上是中断处理函数

void setup(){
  Serial.begin(115200);
  pinMode(Aio, INPUT);
  pinMode(Bio, INPUT);
//只要消耗一个外部中断资源
  attachInterrupt(Aio, Aio_inter, CHANGE);
}
//变量dir在中断里处理,loop中随时调用
void loop(){
  Serial.printf("dir : %d",dir);
  delay(1000); 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值