stm32实战篇
实战第一篇跑马灯
第一篇没什么好说的,没什么新鲜的东西,就是使用cubemx进行建立工程,新建led.c和led.h文件,对引脚进行赋予高低电平,此次不一样的是在led.h文件中对相应的IO口用英文做了宏定义,防止以后进行重复混乱调用。
1 |
|
实战第二篇按键检测
硬件消抖
首先是硬件的设计,按下按键不会立即响应,有波纹信号,不方便检测需要进行滤波消抖。可以利用电容的放电延迟达到消除抖动的目的,这样只需要检测引脚的电平。
软件消抖
当检测到按键状态变化后,先等待一个10ms左右的延时时间,让抖动消失后再进行一次按键状态检测,如果与刚才的状态相同,就是稳定了,但是有局限性。
查询相关IO口在cubemx中进行设置为输入状态。由于引脚的默认电平受按键电路影响,所以设置成“浮空/上拉/下拉”模式均没有区别。
arm汇编指令集
栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部 SRAM 的大
小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。如果某一天,你
写的程序出现了莫名奇怪的错误,并进入了硬 fault 的时候,这时你就要考虑下是不是栈不够大,
溢出了。堆主要用来动态内存的分配
RCC时钟树
设置系统时钟 SYSCLK、设置 AHB 分频因子(决定 HCLK 等于多少)、设置 APB2 分频因子(决
定 PCLK2 等于多少)、设置 APB1 分频因子(决定 PCLK1 等于多少)、设置各个外设的分频因子;
控制 AHB、APB2 和 APB1 这三条总线时钟的开启、控制每个外设的时钟的开启。
一般是:PCLK2 = HCLK = SYSCLK=PLLCLK = 72M,
PCLK1=HCLK/2 = 36M
HSE 是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从 4-16MHZ 不等。当
使用有源晶振时,时钟从 OSC_IN 引脚进入,OSC_OUT 引脚悬空,当选用无源晶振时,时钟从
OSC_IN 和 OSC_OUT 进入,并且要配谐振电容。
系统时钟 SYSCLK 经过 AHB 预分频器分频之后得到时钟叫 APB 总线时钟,即 HCLK。
APB2 总线时钟 PCLK2 由 HCLK 经过高速 APB2 预分频器得到,HCLK2 属于高速的总线时钟,片上
高速的外设就挂载到这条总线上。APB1 总线时钟 PCLK1 由 HCLK 经过低速 APB 预分频器得到,PCLK1 属于低速的总线时钟,最高为 36M,片上低速的外设就挂载到这条总线上,比如 USART2/3/4/5、SPI2/3,I2C1/2 等。
USB 时钟是由 PLLCLK 经过 USB 预分频器得到,USB 对时钟要求比较高,所以 PLLCLK 只能是由 HSE 倍频得到,不能使用 HSI 倍频。
ADC 时钟由 PCLK2 经过 ADC 预分频器得到。
RTC 时钟可由 HSE/128 分频得到,也可由低速外部时钟信号 LSE 提供,频率为 32.768KHZ,也可由
低速内部时钟信号LSI提供。独立看门狗的时钟由 LSI 提供,且只能是由 LSI 提供,LSI 是低速的内部时钟信号,频率为 30~60KHZ 直接不等,一般取 40KHZ。
中断应用
在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx,用来配置外部中断的优先级,IPR宽度为 8bit,原则上每个外部中断可配置的优先级为 0~255,数值越小,优先级越高。如果有多个中断同时响应,抢占优先级高的就会抢占抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。
IRQn:用来设置中断源
PreemptionPriority:抢占优先级
SubPriority:子优先级
外部中断
EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的 20 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。
产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
cubemx进行引脚配置,对相应的IO引脚选择GPIO_EXITx,xi表示挂载在中断线几,如GPIO_EXTI0就是挂在中断线0上。
开启下降沿触发中断:即在 按下按键时 电平由高变为低时触发,则在 GPIO mode
中选择 External Interrupt Mode with Falling edge trigger detection
开启上升沿触发中断:即在 按下按键后松开时 电平由低变为高时触发,则在 GPIO mode
中选择 External Interrupt Mode with Rising edge trigger detection
开启下降沿上升沿都触发中断:即在 按下时触发,松开时再次触发,则在 GPIO mode
中选择 External Interrupt Mode with Rising/Falling edge trigger detection
如果硬件上已外部上拉或下拉,则在GPIO Pull-up/Pull-down
中选择 No pull-up and no pull-down
既不上拉也不下拉。
如果硬件外部没有上拉,则在GPIO Pull-up/Pull-down
中选择 Pull-up
内部上拉电阻。
如果不希望电平跳变事件触发中断,就配置为事件模式,反之,配置为中断模式。
中断执行流程为先中断初始化,使用中断可以避免使用论询来检测,发生电平变化触发外部中断,进入中断服务函数,中断服务函数中会调用中断处理公用函数(使用cubemx会在stm32f1xx_it.c中自动生成),中断处理公用函数中会检测标志位,并清零执行回调函数,终端中要执行的事情就放入中断回调函数中。
可以在stm32f1xx_it.c中看到
1 | void EXTI4_IRQHandler(void) |
go to Defnition of HAL_GPIO_EXTI_IRQHandler
1 | void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) |
首先判断并清除中断标志位,然后调用HAL_GPIO_EXTI_Callback(GPIO_Pin);处理中断,同样的方式找到HAL_GPIO_EXTI_Callback的定义,你可以看到这个函数的声明前面有一个__weak声明,这个声明表示这个函数一旦被重新声明,这里的函数就自动失效,其他函数调用的时候就会找到你新定义的同名函数。
串口通讯
通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。串口通讯有很多标准,以下是RS-232标准
由于 RS-232 电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的“TTL 标准”的电平信号,才能实现通讯。电平标准不同分为TTL标准和RS232电平标准
通用同步异步收发器 (Universal Synchronous Asynchronous Receiver and Transmitter) 是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个 UART(UniversalAsynchronous Receiver and Transmitter),它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。
串口通信有三种方式,分别为论询方式、中断方式、DMA方式。串口的通讯协议由开始位,数据位,校验位,结束位构成。一般以一个低电平作为一帧数据的起始,接着跟随 8 位或者 9 位数据位,之后为校验位,分为奇校验,偶校验和无校验,最后以一个先高后低的脉冲表示结束位,长度可以设置为 0.5,1,1.5 或 2 位长度。
当使用校验位时,串口传输的长度将是 8 位的数据帧加上 1 位的校验位总共 9 位,此时 USART_CR1 寄存器的 M 位需要设置为 1,即 9 数据位。将 USART_CR1 寄存器的 PCE 位置 1 就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启动了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收
数据时如果出现奇偶校验位验证失败,会见 USART_SR 寄存器的 PE 位置 1,并可以产生奇偶校验中断。使能了奇偶校验控制后,每个字符帧的格式将变成:起始位 + 数据帧 + 校验位 + 停止位
什么是硬件流控呢?流控的概念源于 RS232 这个标准,在 RS232 标准里面包含了串口、流控的定义。大家一定了解,RS232 中的“RS”是Recommend Standard 的缩写,即”推荐标准“之意,它并不像 IEEE-1284、IEEE-1394 等标准,是由“委员会定制”。因而,不同的厂商在做 RS232 时,多少会有不同,流控也都会存在差异。
为什么需要流控?
数据在两个串口之间进行通讯的时候常常会出现丢失数据的现象,比如两台计算机或者是一台计算机和一个单片机之间进行通讯,当接收端的数据缓冲区已经满了,这个时候如果还有数据发送过来,因为接收端没有时间进行处理,那这样的数据就有可能会丢失。在工业现场或者其他领域,经常会遇到这种问题,本质原因是速度不匹配、处理能力不匹配。比如单片机的主频只有20M或30M,ARM的处理能力可能是200M,PC机的处理能力是几个G,这种处理能力的不匹配造成了传输的时候数据容易丢失。
硬件流控就是来解决这个速度匹配的问题。它的基本含义非常简单,当接收端接收到的数据处理不过来时,就向发送端发送不再接收的信号,发送端接收到这个信号之后就会停止发送,直到收到可以继续发送的信号再继续发送。因此流控本身是可以控制数据传输的进度,进而防止数据丢失。
一般常用的流控方式有两种:硬件流控和软件流控。
硬件流控和软件流控的区别
软件流控是以特殊的字符来代表从机已经不能再接收新的数据了,基本的流程就是从机在接收数据很多的时候或主动给发送端发送一个特殊字符,当发送端接收到这个特殊字符后就不能再发送数据了。
软件流控很方便,不需要增加新的硬件,还是以前的TX、RX,但是使用了软件流控,它本身的字符也是数据,这个数据只不过是说在软件里把它设置了一个特殊的含义。如果它是一个全双工的通讯,在给另一个串口发送数据的时候如果也包含了这样一个特殊字符,对方就会误以为我让它不要再发送数据了,会有一定的概率出现错误,而硬件流控就不需要考虑这方面,只需要使用 CTS 和 RTS,所有的数据都是由硬件来操作的。具体可以看
1 | 1、 |
(具体配置) 【STM32】HAL库——串口中断通信(二)_Q大帅的博客-CSDN博客_hal 串口中断
当printf打印不好使时是因为工程中没有选Micro USB
() STM32 HAL库串口串口通信基础知识+HAL库代码理解
DMA-直接存储访问
DMA是单片机外设,不占用CPU,传输数据时候CPU可以做别的。如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求,DMA 收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。DMA有12个可独立编程通道,每个通道对应不同的外设DMA请求,可以接受多个请求,但同时只能接受一个。仲裁器,处理响应顺序的问题,分为软件阶段和硬件阶段,可以在 DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高。
MA 传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储器到存储器。具体的方向 DMA_CCR 位 4 DIR 配置:0 表示从外设到存储器,1 表示从存储器到外设。
更多原理可参看 DMA原理
在cubemx的配置只需要加上相应设备的DMA模式便可以生成代码进行使用。
I2C协议
首先分为物理层和协议层,两方面来看。
物理层:
它是一个支持设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。
一个 I2C 总线只使用两条总线线路,一条双向串行数据线 (SDA) ,一条串行时钟线 (SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。
总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
具有三种传输模式:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模式
协议层:
I2C 的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。
S 表示由主机的 I2C 接口产生的传输起始信号 (S),这时连接到 I2C 总线上的所有从机都会接收到这个信号。
起始信号产生后,所有从机就开始等待主机紧接下来广播的从机地址信号 (SLAVE_ADDRESS)。在I2C 总线上,每个设备的地址都是唯一的,当主机广播的地址与某个设备地址相同时,这个设备就被选中了,没被选中的设备将会忽略之后的数据信号。根据 I2C 协议,这个从机地址可以是 7位或 10 位。在地址位之后,是传输方向的选择位,该位为 0 时,表示后面的数据传输方向是由主机传输至从机,即主机向从机写数据。该位为 1 时,则相反,即主机由从机读数据。从机接收到匹配的地址后,主机或从机会返回一个应答 (ACK) 或非应答 (NACK) 信号,只有接收
到应答信号后,主机才能继续发送或接收数据。
若是传输为写数据方向,接收到应答信号后,主机开始正式向从机传输数据 (DATA),数据包的大小为 8 位那么主机每发送完一个字节数据,都要等待从机的应答信号 (ACK)。
若配置的方向传输位为“读数据”方向,接收到应答信号后,从机开始向主机返回数据 (DATA),数据包大小也为 8 位,从机每发送完一个数据,都会等待主机的应答信号 (ACK)。
SCL处于1时, SDA由高变低↓—>Start
图中末尾P为结束信号: SCL=1, SDA 由低变高
数据传送: 每次数据传送都是8个字节; SCL=1时, SDA的数据不可以变化, 只有SCL为低电平, 数据线的数据才可以变化;
IIchal相关函数分析 015] [STM32] IIC协议详解与HAL库相关函数分析_柯西的彷徨的博客-CSDN博客)
SPI协议
SPI是一种高速全双工的通信总线
物理层
SPI 通讯使用 3 条总线及片选线,3 条总线分别为 SCK、MOSI、MISO,片选线
从设备选择信号线,常称为片选信号线,也称为 NSS、CS设备的其它信号线 SCK、MOSI 及 MIS O 同时并联到相同的 SPI 总线上,即无论有多少个从设备,都共同只使用这 3 条总线;而每个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。而 SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以 SPI 通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号。
SCK :时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样。
MOSI :主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。
MISO(Master Input,,Slave Output):主设备输入/从设备输出引脚。主机从这条信线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。
NSS 信号线由高变低,是 SPI 通讯的起始信号。NSS 是每个从机各自独占的信号线,当从机在自己的 NSS 线检测到起始信号后,就知道自己被主机选中了,开始准备与主机通讯。在图中的标号处,NSS 信号由低变高,是 SPI 通讯的停止信号,表示本次通讯结束,从机的选中状态被取消。
观察图中的标号处,MOSI 及 MISO 的数据在 SCK 的上升沿期间变化输出,在 SCK 的下降沿时被采样。即在 SCK 的下降沿时刻,MOSI 及 MISO 的数据有效,高电平时表示数据“1”,为低电平时表示数据“0”。在其它时刻,数据无效,MOSI 及 MISO 为下一次表示数据做准备。