STM32_Day04(SPI + 中断)
1.SPI协议
1.1 SPI总线介绍
SPI接口是Motorola (https://www.motorola.com/us/)首先提出的全双工三线/四线同步串行外围接口采用主从模式(Master Slave)架构。
时钟由Master控制,在时钟移位脉冲下,数据按位传输,高位在前,低位在后(MSB first);SPI接口有2根单向数据线,为全双工通信。
SPI总线被广泛地使用在FLASH、ADC、LCD等设备与MCU间,要求通讯速率较高的场合。
1.2 SPI总线物理(拓扑结构)
SPI总共有4根总线,分别是:设备选择线、时钟线、串行输出数据线、串行输入数据线。
(1)MOSI:主器件数据输出,从器件数据输入
(2)MISO:主器件数据输入,从器件数据输出
(3)SCLK :时钟信号,由主器件产生
(4)/SS:从器件使能信号,由主器件控制(片选)
1.3 SPI总线协议
起始信号: NSS信号线由高变低,是SPI通讯的起始信号 (NSS是片选信号,使能信号)
结束信号:NSS信号由低变高,是SPI通讯的停止信号
数据传输:SPI使用MOSI及MISO信号线来传输数据,使用SCK信号线进行数据同步。MOSI及MISO数据线在SCK的每个时钟周期传输一位数据高位在前低位在后,且数据输入输出是同时进行的。SPI每次数据传输可以 8 位或 16 位为单位,每次传输的单位数不受限制。
1.4 SPI的四种通信模式
在SPI操作中,最重要的两项设置就是时钟极性(CPOL)和时钟相位(CPHA)这两项即是主从设备间数据采样的约定方式。
SPI有四种通信模式:
时钟极性CPOL : 设置时钟空闲时的电平
当CPOL = 0 ,SCK引脚在空闲状态保持低电平;
当CPOL = 1 ,SCK引脚在空闲状态保持高电平。
时钟相位CPHA :设置数据采样时的时钟沿
当 CPHA=0 时,MOSI或 MISO 数据线上的信号将会在 SCK时钟线的奇数边沿被采样
当 CPHA=1时, MOSI或 MISO 数据线上的信号将会在 SCK时钟线的偶数边沿被采样
数据线被采样,都是等待数据线变化稳定半个时钟周期进行采样。
通信模式的设置:
由CPOL及CPHA的不同状态,SPI分成了四种模式,主机与从机需要工作在相同的模式下才可以正常通讯,因此通常主机要按照从机支持的模式去设置
2.LCD液晶显示屏
液晶的组成
某些物质在熔融状态或被溶剂溶解之后,尽管失去固态物质的刚性,却获得了液体的易流动性,并保留着部分晶态物质分子的各向异性有序排列,形成一种兼有晶体和液体的部分性质的中间态,这种由固态向液态转化过程中存在的取向有序流体称为液晶。
物理特点
当通电时导通,排列变得有秩序,使光线容易通过;不通电时排列混乱,阻止光线通过。
液晶显示屏内部构造
颜色深度
① R,G,B三基色组合形成各种颜色。
② 能显示的颜色数由RGB的数字信号的位数来决定
例如,以3位数字信号来表示颜色深度
RGB24表示(24位真彩色)
R:8
G:8
B:8
所以他能显示的颜色深度就是2^8 *2^8 *2^8
STM32G030开发板板载的显示屏是RGB16也称为RGB565
颜色深度: 2^5 *2^6 *2^5
由一个16位的数据控制一个像素点的颜色显示
让一个像素点显示正红色 :1111 1000 0000 0000 0xf800
让一个像素显示正蓝色 :0000 0000 0001 1111 0x1f
3.点亮LCD显示屏
1.查看原理图
底板原理图
2.配置CubeMX工程
4.图片显示
1)怎么制作图片
5.字符显示
英文字符和数字字符包括标点符号在font.h中已经生成好了字模,因此不需要再次取模
直接调用字符串显示函数即可
6.汉字显示
打开汉字取模软件
定义一个char类型的二维数组,并初始化为汉字字模数据
调用汉字显示函数,按要求传递参数即可
7.中断系统
7.1 基本概念
在处理器中,中断相当是对于突发事件的处理过程。
当遇到内部/外部的紧急事件需要处理时,暂时中止当前程序,转而去处理紧急事件,
待处理完毕后,再返回被打断的程序继续向下运行。
暂停:保护现场
继续:恢复现场
7.2 中断的意义
中断能够对突发事件进行及时处理,实现程序的并行化(时间片),进而提高CPU的工作效率。当发生突发事件时,比如外部触发的输入信号、定时器溢出等,中断会立即打断正在执行的程序,转而执行中断服务函数(ISR)来处理该事件。
关于并行化解释:
在STM32中,程序的并行化是指通过使用中断机制,使得当发生突发事件时,可以立即处理该事件,而不需要等待当前正在执行的程序完成。
传统的程序执行方式是顺序执行,即按照代码的顺序逐行执行。这种方式存在一个问题,即当程序执行某个任务时,如果发生了突发事件,程序需要等待当前任务执行完毕才能响应事件。这可能导致事件处理延迟,影响系统的响应速度。
而使用中断机制可以解决这个问题。当发生突发事件时,比如外部输入信号触发的中断,系统会立即打断当前正在执行的程序,转而执行与该事件相关的中断服务函数。中断服务函数可以快速响应事件并处理相应的逻辑,而无需等待当前任务的完成。
通过这种方式,程序的执行可以在某个任务被打断的同时,立即响应其他突发事件。这样就实现了程序的并行化处理,提高了系统的响应速度和效率。
为什么提高效率?
因为CPU对于没有发生的事情是在不停的在轮询(询问有没有发生?)
中断能提高CPU的效率,同时能对突发事件做出实时处理。实现程序的并行化,实现嵌入式系统进程之间的切换。
7.3 中断处理过程
中断处理过程
进入中断
1.处理器自动保存现场到堆栈里(堆栈——内存)
2.{PC, xPSR, R0-R3, R12, LR}
3.一旦入栈结束,ISR便可开始执行(中断服务程序)
退出中断
1.中断前的现场被自动从堆栈中恢复
2. 一旦出栈完成,继续执行被中断打断的指令
3.出栈的过程也可被打断,使得随时可以响应新的中断而不再进行 现场保存
R0 - R12
R13 栈指针 SP : 指向栈顶地址
R14 链接寄存器 LR :存放返回地址
R15 程序计数器 PC :保存要执行的指令地址
示例:
老师正在上课 (正常执行的主程序,线程模式)
班主任叫我去开会 (产生一个中断信号)
暂停讲课,关闭会议,保存笔记 (压栈,保护现场)
根据地址/门牌号去开会 (根据中断向量表跳转到中断服务程序)
开会 (执行中断服务程序)
回到教室继续上课 (恢复现场,继续执行)
7.4 中断体系结构
注:中断和异常的区别
中断是微处理器外部发送的,通过中断通道送入处理器内部,一般是硬件引起的,比如按键中断、串口接收中断,而异常通常是微处理器内部发生的,大多是软件引起的,比如除法出错异常,特权调用异常等待。不管是中断还是异常,微处理器通常都有相应的中断/异常服务程序。
7.5 NVIC
NVIC主要功能
负责管理中断 (CPU的小助理)
1、中断管理
2、支持异常及中断向量化处理
3、支持嵌套中断
1)管理中断事件(清除、挂起)
每一个中断事件都有执行或禁止两种状态,由NVIC负责将中断事件标记为清除和挂起两种状态。 处理器的中断可以电平的形式的,也可以是脉冲形式的,这样中断控制器就可以处理任何中断源。
(当中断执行完成时,NVIC会将中断事件置为清除状态)
2)支持中断向量化处理(向量表)
当中断事件发生时,处理器会将PC(程序计数器 PC :保存要执行的指令地址)设置为一个特定地址(中断事件入口函数的地址),进而跳转到中断服务程序去执行,这就是个中断(异常)向量,因为每一个异常源或者中断事件都会对应一个服务程序的入口地址,将这些地址按照优先级进行排布后,组成的一张表就称为中断(异常)向量表。
Cortex-M0内核可以处理15个内部异常和32个外部中断
STM32G030 只使用了6个内部异常和28个外部中断
向量化处理中断的好处:
传统的处理方式需要软件去完成。采用向量表处理异常,M0处理器会从存储器的向量表中,自动定位异常的程序入口。从发生异常到异常的处理中间的时间被缩减。
3)支持中断嵌套 (优先级)
要启用中断嵌套,首先需要在NVIC模块中配置中断优先级。每个中断都有一个相应的优先级,中断嵌套使得某个中断能够打断正在执行的较低优先级中断,从而及时响应更高优先级的中断请求。
3个固定的优先级,都是负值,不能改变。
四个可编程优先级,用两个bit位表示,00,01,10,11(0、1、2、3)
优先级数值越小,优先级等级越高。
注意
不同优先级的中断同时发生,优先处理优先级编号较小的那个(中断优先级)
同样优先级的中断同时发生,中断向量号较小的那个优先响应(响应优先级)
7.6 EXTI
外部中断控制器
主要功能:产生中断、事件。
产生中断的目的:是将信号送入NVIC,进而运行中断服务程序,实现对应功能,是软件级。
产生事件的目的:是将采集到的一个脉冲信号送到某个外设,进而驱动某些设备做出动作,是电路级别的传输,是硬件级的。
在 STM32G030 中,共有最多 28 中断 / 事件线可用
GPIO 口连接到 16 个外部中断 / 事件线
编号1是信号输入线,EXTI支持产生多达28个外部事件/中断请求。
编号2是边沿检测电路,用于监测上升沿或下降沿信号。
它会根据上升沿触发选择寄存(EXTI_RTSR)和下降沿触发选择寄存器(EXTI_FTSR)对应位的设置来控制信号触发。
边沿检测电路以输入线作为信号输入端,监测是否有边沿跳变,检测到有边沿跳变输出有效信号 1 给编号 3 电路,否则输出无效信号0。
编号3是一个或门电路,信号来源是外部事件或者软件中断/事件寄存器产生。
允许我们通过程序控制EXTI_SWIER就可以启动中断/事件线
编号4是一个与门电路,信号来源是编号3送来的信号和中断屏蔽寄存器的值,
如果中断屏蔽寄存器为0,也不会将信号送到NVIC,
只有编号3送来了中断信号且中断屏蔽寄存器允许产生中断,才会将中断信号送入NVIC.
接下来我们来看看红色虚线指示的电路流程。它是一个产生事件的线路,最终输出一个脉冲信号。
产生事件线路是在编号3电路之后与中断线路有所不同,之前电路都是共用的。
编号5是一个与门电路,信号来源是编号3送来的信号和事件屏蔽寄存器的值,
如果事件屏蔽寄存器为0,不会将信号送到脉冲发生器,
只有编号3送来了信号且事件屏蔽寄存器允许产生事件,才会将信号送入脉冲发生器(编号6), 进而产生脉冲来控制外部设备做出动作。
这样我们可以简单的控制 EXTI_EMR(事件屏蔽寄存器) 来实现是否要产生事件的目的
8.按键中断实验(外部中断)
实验要求:STM32正常执行LED灯闪烁主程序,当检测到按键按下时处理中断事件,通过串口打印“HelloWorld!!!”
按键中断编程步骤分析
1、使能相应的时钟
2、配置GPIO管脚为中断功能
3、设置中断优先级
4、使能相应的中断
5、实现中断服务程序
打开原理图,找到按键的引脚
在main.c的while中完成主程序的编写,即LED灯1s闪烁
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2);
HAL_Delay(500);
打开启动文件starup.s,找到中断向量表
__weak void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Rising_Callback could be implemented in the user file
*/
}
WEAK弱符号
weak 顾名思义是“弱”的意思,所以如果函数名称前面加上__weak 修饰符,我们一般称这个函数为“弱函数”。
加上了__weak 修饰符的函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,
那么编译器就会执行__weak 修饰的函数,并且编译器不会报错。
重写中断回调函数:
9.串口中断实验(内部)
发送完成中断实验
实验要求:主程序发送一句字符串“HelloWorld”,当这条字符串发送完成时触发中断事件,调用中断服务程序发送“HelloHello”
串口中断编程步骤分析
1、使能相应的时钟
2、配置GPIO管脚为串口功能
3、设置中断优先级
4、使能相应的中断
5、实现中断服务程序
找到串口1的中断服务程序
当发送结束时调用UART_EndTransmit()
找到发送完成中断回调函数:
重写发送完成回调函数:
作业
1. 显示屏显示计时时间,格式为00:00:00,时间以秒为单位自加,
当检测到按键按下之后,时间归零,继续从0开始计时。
2.尝试实现接收完成中断,当接收到4个字符时,产生接收完成中断事件,并在服务程序中输出“Very OK!”
完成作业后,拍视频发到群里