炒了个叫“嵌入式”的大杂烩,请大家品尝

本锅主要炒STM32、FreeRTOS、以太网通信等饭菜,当然不限于这几道。持续更新,后续会炒CMake、C++、网络编程等内容。

1. Cortex-M片

在这里插入图片描述

为了使软件兼容,使用M3内核的芯片都共同遵循CMSIS标准,ARM微控制器软件接口标准。

Cortex-M3内核芯片,内核结构都是一样的,不同的是它们存储器容量、片上外设、IO及其他模块的区别。

2. STM32库函数工程模版搭建

STM32库函数模版搭建文章链接

3. C语言中的一些小知识点

ifndef

条件编译的作用:1.避免重复编译;2.依条件编译。

extern

C语言中extern 可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇 到此变量和函数时在其他模块中寻找其定义 。 这里面要注意,对于**extern申明变量可以多次,但定义只有一次。**在我们的代码中你会看到看到这样的语句:

extern u16 USART_RX_STA;
typedef与define
  • define是C语言中的预处理命令,用于宏定义。
  • typedef用于对现有类型创建一个新名字,类型别名。

4. STM32时钟概述

时钟系统是CPU的脉搏,非常重要。STM32时钟系统比较复杂,不像51单片机一个时钟就可以解决一切,它是由有五个时钟源组成,HSIHSELSILSEPLL。由于STM32本身非常复杂,外设非常多,并不是所有外设都需要系统时钟那么高的频率。同一个电路时钟越高功耗越大,抗电磁干扰能力也就越弱,所以STM32采用多时钟源的方法来解决这些问题。

5. 端口复用与端口重映射

STM32有许多内置外设,这些外设的外部引脚都是与GPIO复用的。简单来说,一个GPIO如果可以复用为内置外设的功能引脚,那当这个GPIO作为内置外设使用的时候,就复用

使用复用功能的时候,至少要使能这个GPIO时钟和复用的外设时钟。

端口重映射则指的是服用功能重新映射到其它引脚上。如USART1的重映射:
在这里插入图片描述

重映射的话,还要再使能AFIO功能时钟,然后调用重映射函数。另外外部中断也需要开启AFIO时钟。

串口1重映射:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能 GPIOB 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USAR T1, ENABLE);//使能串口 1 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//使能 AFIO 时钟
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);//开启 重映射:

6. GPIO

每一个IO端口都有7个寄存器来控制,分别是配置模式的CRLCRH、数据寄存器IDRODR、置位/复位寄存器BSRR、锁寄存器LCKR。另外GPIO有八种模式
1、输入浮空GPIO_Mode_IN_FLOATING = 0x04
2、输入上拉GPIO_Mode_IPU = 0x48
3、输入下拉GPIO_Mode_IP D = 0x28
4、模拟输入 GPIO_Mode_AIN =0x0
5、开漏输出 GPIO_Mode_Out_OD = 0x14
6、推挽输出 GPIO_Mode_Out_PP = 0x10
7、推挽式复用功能 GPIO_Mode_AF_PP = 0x18
8、开漏复用功能GPIO_Mode_AF_OD = 0x1C

跑马灯实验

7. USART串口

USART, 即通用同步/异步穿行接收/发送器。

UART与USART区别

UART是通用异步收发器,但从名字来看,USART在UART基础上增加了同步功能,可以理解为是UART的增强型。在做异步通信的时候两者没什么区别,但在同步通信时区别就很明显了。

同步通信与异步通信蛀主要的区别在于有无时钟,前者有公共时钟,总线上所有设备按统一的时序、传输周期进行信息传输。后者没有公共时钟,没有固定传输周期,采用应答通信。主要借助波特率。

简单的说,“同步”就是发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。 “异步”就是发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。异步通信发送方式下,在每一个字符的开始和结束分别加上开始位和停止位,以便使接收端能够正确地将每一个字符接收来。

单工/半双工/全双工

在这里插入图片描述

单工数据传输只支持才一个方向上传输,可以理解为只能A发B收,只有一条传输线。

半双工数据传输允许数据在两个方向上传输,但某一时候只允许数据在一个方向上传输,比如IIC通信,主机发还是从机发,同一时间内只能有一个方向。

全双工数据通信允许数据同时在两个方向上传输,至少需要两条线,要求发送设备和接受设备都有独立的接收和发送能力。如uart、spi。

USART一般步骤及485收发数据

usart实现485通信

RS232、RS485与Modbus485三者区别

RS232是在电气层面对串口通信进行了规定,就好比串口通信协议是马路上的车,RS232就是这条马路,它规定了马路的标准。RS485传输电平信号接口的信号电平值较高(信号“1”为“-3V至-15V”,信号“0”为“3至15V”),与TTL电平兼容使用时需要电平转换电路。
RS485也是一种电气层面的标准,考虑到RS232抗干扰能力弱,另外电平值较高易损坏芯片这方面,RS485采用差分信号逻辑来表示信号逻辑“1”与逻辑0“,降低接口信号电平并与TTL电平兼容。
Modbus485则是一种通信协议。

几种中断的区别

  • 外部中断IO触发的,可以理解为外部输入引起的中断。
  • 定时器中断与串口中断都是与内部中断,由处理器内部的定时器和串口模块触发的中断。

8. 看门狗

独立看门狗

独立看门狗由内部专门的40khz低速时钟驱动,即使主时钟发生故障它也仍有效。单片机系统在受到外界干扰(如电磁干扰)可能会出现程序跑飞的现象导致出现死循环,看门狗就是为避免这种情况发生。看门狗的作用是在一定时间内没有接收到喂狗信号,便会将处理器进行复位重启。

在键值寄存器 (IWDG_KR) 中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复
位值 0xFFF 递减计数。当计数器计 数到末尾 0x000 时,会产生一个复位信号 (IWDG_ RESET
无论何时,只要键寄存器 IWDG_KR 中被写入 0xAAAA IWDG_RLR 中的值就会被重新加载
到计数器中从而避免产生看门狗复位 。

窗口看门狗

串口看门狗是用来监测由外部干扰、或不可预见的逻辑条件造成的软件故障。窗口看门狗喂狗需要在特定的时间段内,如下图。在刷新窗口外喂狗都会发生复位。
在这里插入图片描述

独立看门狗与窗口看门狗的区别
  • 独立看门狗没有中断,窗口看门狗有中断
  • 独立看门狗有硬件软件之分,窗口看门狗只能软件控制
  • 独立看门狗只有下限,窗口看门狗有下限和上限
  • 独立看门狗是12位递减的。窗口看门狗是7位递减的
  • 独立看门狗是用的内部的大约40KHZ RC振荡器,窗口看门狗是用的系统时钟APB1ENR
  • 独立看门狗(IWDG)是独立于系统之外,因为有独立时钟,所以不受系统影响的系统故障探测器。主要用于监视硬件错误。
  • 窗口看门狗(WWDG)是系统内部的故障探测器,时钟与系统相同。如果系统时钟不走了,这个狗也就失去作用了。主要用于监视软件错误。

窗口看门狗(WWDG)是系统内部的故障探测器,时钟与系统相同。如果系统时钟不走了,这个狗也就失去作用了。主要用于监视软件错误。

独立看门狗(IWDG)没有中断功能,只要在计数器减到0(下限)之前,重新装载计数器的值,就不会产生复位,独立看门够有硬件和软件之分,硬件是通过烧写器的“设定选项几节等”配置,一旦开启了硬件看门狗,那么就停不下来了,只能在重新配置“设定选项几节等”才能关掉硬件看门狗,软件看门狗只需要设置IWDG->KR=0XCCCC;就可以启动看门狗了,软件狗可以在系统复位时关掉,如果在在初始化里开启软件看门狗,那就开启了软件看门狗,独立看门狗是12位递减的寄存器,使用片子内部的RC振荡器,这个振荡器是关不掉的。

窗口看门狗(WWDG)有中断,这个中断的作用是在计数器达到下限0x40的时候,产生中断,让你喂狗,如果你不喂狗,计数器的值变为0x3f的时候,将会产生系统复位,即使是喂狗,也应该在中断里快速喂狗,要不时间长了计数器减一也会变成0x3f产生复位,这个时间根据芯片手册的公式进行计算即可得到,窗口看门狗只有软件开启方式,还有一个上限值,这个值如果大于计数器的初始值,那么就没有任何作用了,这个值小于计数器的初始值得时候,当计数器的值大于上限值时你对计数器进行装载,将会产生复位,只有在计数器减到小于上限值时,你才能重新装载计数器,意思就是说只有计数器的值在上限值和下限值之间你才能装载计数器,否则就会产生系统复位,当上限值小于下限值,也没有意义。

9. 定时器

STM32有8个定时器,分别是2个高级定时器TIM1TIM8,4个通用定时器TIM2~TIM8,2个基本定时器TIM5TIM6。高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。
在这里插入图片描述

计数器模式

三种计数模式,向上、向下、向上/向下(中心对齐)计数模式。

  • 向上计数模式:从0加到某个数之后产生溢出事件。
  • 向下计数模式:从某个数减到0之后产生溢出事件。
  • 中心对齐模式:计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并产生一个向下溢出事件;然后再从0开始重新计数。
定时器工作原理

定时器框图
定时器这块4部分组成:时钟产生、时基单元、输入捕获、输出比较
时钟产生: 计数器时钟可由内部时钟1CK_INT、外部时钟模式1TIx、外部时钟模式2ETR、内部触发输入ITRx这些时钟源来提供。

内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1 而作为另一个定时器Timer2的预分频器。

时基单元: 包括计数器寄存器TIMx_CNT、预分频器寄存器TIMx_PSC、自动装载寄存器TIMx_ARR
输入捕获通道检测TIMx_CHx通道上的边沿信号在边沿信号发生跳变的时候将当前定时器的值TIMx_CNT存到对应的捕获比较寄存器TIMx_CCRx中,完成一次捕获。 同时,还可以配置捕获是否触发中断/DMA等。

在这里插入图片描述

  • IC1、2和IC3、4可以分别通过软件设置将其映射到TI1、TI2和TI3、TI4;
  • 4个16位捕捉比较寄存器可以编程用于存放检测到对应的每一次输入捕捉时计数器的值
  • 当产生一次捕捉,相应的CCxIF标志位被置1;同时如果中断或DMA请求使能,则产生中断或DMA请求。
  • 如果当CCxIF标志位已经为1,当又产生一个捕捉,则捕捉溢出标志位CCxOF将被置1。

输出比较通道: 定时器通过对预设的比较值与定时器的值做匹配比较之后,并依据相应的输出模式从而实现各类输出。 如PWM输出、电平翻转、单脉冲模式、强制输出等。一般来说,STM32的通用定时器和高级定时器都具有比较输出功能,不同的定时器可能通道数量上有差异。

定时器一般配置思路
  • step1:定时器时钟使能;
  • step2:初始化定时器参数,自动装载值、分频系数、计数方式等;
TIM_TimeBaseSt ructure.TIM_Period = arr; //设置自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 设置时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上
计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIM3
  • step3:允许更新中断,当然也可以是别的,这里以这个为例;
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
  • step4:NVIC配置,通道、优先级等;
  • step5:使能定时器;
TIM_Cmd(TIM3, ENABLE);
  • step6:编写中断服务函数;
void TIM3_IRQHandler(void); //TIM3

注:使用前要先配置中断分组

输入捕获一般步骤
  • 初始化定时器和通道对应IO的时钟;
  • 初始化IO口,模式为输入。调用函数:GPIO_Init()
  • 初始化定时器ARR,PSC。调用函数:TIM_TimeBaseInit()
  • 初始化输入捕获通道。调用函数:TIM_ICInit()
  • 如果要开启捕获中断。调用函数:TIM_ITConfig()NVIC_Init()
  • 使能定时器。调用函数:TIM_Cmd()
  • 编写中断服务函数。调用函数:TIMx_IRQHandler()

10. ADC/DAC

STM32f103系列有3个ADC,精度为12位,每个ADC最多有16个外部通道。其中ADC1和ADC2都有16个外部通道,ADC3一般有8个外部通道,各通道的A/D转换可以单次、连续、扫描或间断执行,ADC转换的结果可以左对齐或右对齐储存在16位数据寄存器中。ADC的输入时钟不得超过14MHz,其时钟频率由PCLK2分频产生。

STM32中的ADC用的是12位逐次逼近型的模数转换器。ADC转换步骤是采样、保持、量化、编码。采样保持实际上可看作一个过程。量化和编码可看作是ADC逐次比较的过程。

逐次逼近型ADC由比较器、D/A转换器、缓冲寄存器和若干控制逻辑电路构成。原理是从高位到低位逐位比较,首先将缓冲寄存器各位清零;转换开始后,先将寄存器最高位置1,把值送入D/A转换器,经D/A转换后的模拟量送入比较器,称为 Vo,与比较器的待转换的模拟量Vi比较,若Vo<Vi,该位被保留,否则被清0。然后,再置寄存器次高位为1,将寄存器中新的数字量送D/A转换器,输出的 Vo再与Vi比较,若Vo<Vi,该位被保留,否则被清0。循环此过程,直到寄存器最低位,得到数字量的输出。

规则通道组和注入通道组

规则通道相当于你正常运行的程序,而注入通道就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。

转换时间计算

STM32 ADC总转换时间 = 采样时间 + 12.5个ADC周期。ADC是挂在在APB2总线上的,所以ADC得时钟是由PCLK2(72MHz)经过分频得到的,可以是2/4/6/8分频,假设分频因子是8,则得到的时钟频率为9MHz。一个ADC周期占用的时间 = 1/9MHz = 0.11us。假设采样时间设置为ADC_SampleTime_1Cycles5, 即1.5个周期一次转换总的时间 = 1.5周期+12.5周期 = 14周期 = 14x0.1111us = 1.55us。 两次采样最小间隔时间就是1.55us

时间换算:

  • 1s【秒】 = 1000ms【毫秒】
  • 1ms【毫秒】 = 1000μs【微秒】
  • 1μs【微秒】 = 1000ns【纳秒】
  • 1ns 【纳秒】= 1000ps【皮秒】
电压转换

要知道,转换后的数据是一个12位的二进制数,我们需要把这个二进制数代表的模拟量(电压)用数字表示出来。比如测量的电压范围是0~3.3V,转换后的二进制数是x,因为12位ADC在转换时将电压的范围大小(也就是3.3)分为4096(2^12)份,所以转换后的二进制数x代表的真实电压的计算方法就是:y=3.3* x / 4096

一般步骤
  • 开启相关时钟:STM32F103ZET6的 ADC 通道1在 PA1上,所以,我们先要使能 GPIOA 的时钟 和 ADC1时钟 ,然后设置 PA1 模拟输入
  • 复位ADC,同时设置分频因子。如RCC_ADCCLKConfig(RCC_PCLK2_Div6);
  • 初始化ADC1参数,设置工作模式及规则序列等。
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC 工作模式 独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //AD 单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //AD 单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC 数据右 对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的 ADC 通道的数目 1
ADC_Init(ADC1, &ADC_InitStructure); //根据指定的参数初始化外设 ADCx
  • 使能ADC并校准,转换器,执行复位校准和 AD 校准,注意这两步是必须的!不校准将导致结果很不准确。

执行复位校准的方法是:ADC _ResetCalibration(ADC1)
执行ADC 校准的方法是:ADC_StartCalibration(ADC1); 开始指定 ADC1 的校准状态
记住,每次进行校准之后要等待校准结束。这里是通过获取校准状态来判断是否校准是否结束。下面我们一一列出复位校准和AD 校准的等待结束方法:
while(ADC_GetResetCalibrationStatus(ADC1)); 等待复位校准结束
while(ADC_GetCalibrationStatus(ADC1)); 等待校 AD 准结束

  • 读取ADC值

接下来我们要做的就是设置规则序列 1 里面的通道 ,采样顺序以及通道的采样周期, 然后启动 ADC 转换。在转换结束后,读取ADC转换结果值就是了。

11. FreeRTOS

为什么要RTOS开发?
【1.模块化】
我们在做裸机开发的时候,不可避免的会在主程序里面写一个大循环,所有业务功能逻辑都在这个大循环中,即使你通过分文件分函数的方式使得主循环看着不那么冗余,但实际上这些代码是挤在一起的,不可拆分。

举一个非常贴切的例子,在一些使用看门狗的项目中,如果使用 delay 延时函数,那得注意点,万一延时过长,主函数来不及喂狗,看门狗就被触发了。最后会产生这样一种感觉,一个简简单单的 delay 还得考虑喂狗功能,裸机开发时操的心太多了,自然无法应用在大型项目中。

使用了操作系统以后,整个软件的工作被拆分成了由多个任务来构成(也会被称为线程),每个线程有自己独立的运行空间,即线程堆栈,这个时候每个线程你玩你的,我做我的,咱们大家互补干涉,模块化程度得到很好的提高。

【2.并发性】
裸机程序中几乎所有的业务裸机都是串行起来工作的,而且每个业务逻辑中或多或少都会有一些delay这样的循环等待,这样就会导致软件执行效率低。当然裸机有也是有中断的,可以通过中断来进行调度,但复杂耗时的业务裸机不适合放在中断里执行。

从并发的角度来看,各个线程在使用 delay/事件等待 这类函数时,会自动的让出 CPU 给其他有需要的线程,不仅书写 delay 延时函数操的心少了,整个 CPU 的利用率也得到了提高,最终提升并发性。

【3.实时性】
裸机软件变得庞大以后,主程序中那么大的一个 while(1) 循环,代码耦合严重,到处都是 delay 延时,要保证实时性几乎是不可能的。

再来看实时性,像 ucos/RT-Thread 这些 RTOS 本身就被设计为实时的操作系统,各个线程都有不同的优先级别,重要的线程可以设为高优先级,不重要的线程可以降低优先级,做好全局的统筹规划后,这样整个软件的实时性也能得到保证。

【4.灵活性】
超级循环体系结构的一个关键问题是定时和响应时间,因为它们是由代码结构决定的,如果进行修改或添加,它们会发生变化。
RTOS带来了这些方面的便捷。

基于优先级的抢先式RTOS允许根据任务的实时要求对任务进行优先级排序。具有严格时间约束的任务能够优先于那些具有更大调度灵活性的任务,从而提高应用程序对时间关键事件的响应能力。虽然可以在裸机上实现某种形式的抢先调度,但它的范围有限。

在这里插入图片描述

FreeRTOS移植:FreeRTOS移植
任务创建/删除:FreeRTOS创建/删除任务

在这里插入图片描述

任务挂起与恢复:FreeRTOS任务挂起与恢复
RTOS中断管理:RTOS中断管理

STM32 的中断即要设置中断优先级分组又要设置抢占优先级和子优先级,看起来十分复杂。 其实对于FreeRTOS,FreeRTOS 的官方强烈建议STM32 在使用FreeRTOS 的时候,使用中断优先级分组4(NVIC_PriorityGroup_4)即优先级配置寄存器的高4 位全部用于抢占优先级不使用子优先级,这么一来用户就只需要设置抢占优先级即可。

进出临界区 :临界区是指那些必须完整运行的区域,在临界区中的代码必须完整运行,不能被打断。FreeRTOS的做法是在进入临界区时关闭那些受管理的中断,出临界区的时候再将它们开启。像软件模拟的通信协议,在通信时,必须严格按照通信协议的时序进行而不能被打断,就需要用到临界区保护了。

任务优先级与中断优先级逻辑是相反的
在这里插入图片描述

列表与列表项:列表与列表项
队列:队列

12. STM32网络开发CH395Q系列

根据网络接口通信方式的不同,以太网接入单片机分为两种方案传统的软件TCP/IP协议栈方案硬件TCP/IP协议栈方案。在介绍方案之前,有如下知识需要了解:

PHY相当于实现了osi协议中物理层的功能。定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。物理层的芯片称之为PHY。

MAC媒体访问控制子层协议,对应于7层协议中数据链路层的下半部分,主要负责控制与连接物理层的物理介质。

MII即媒体独立接口,也叫介质无关接口。它是IEEE-802.3定义的以太网行业标准。它包括一个数据接口,以及一个MAC和PHY之间的管理接口。数据接口包括分别用于发送器和接收器的两条独立信道。每条信道都有自己的数据、时钟和控制信号。

MAC 和 PHY,一个是数据链路层,一个是物理层;两者通过 MII 传送数据。

传统的软件TCP/IP协议栈以太网接入方案,这种方案有集成了MACMCU+PHY组层以实现以太网物理连接。LwIP协议栈实现了应用层、传输层和网络层的功能。这就实现了osi的网络模型。如下图。
在这里插入图片描述

硬件TCP/IP协议栈以太网接入方案,全硬件TCP/IP 协议栈是将传统的软件协议TCP/IP 协议栈用硬件化的逻辑门电路来实现芯片内部完成TCPUDPICMP多种应用层协议并且实现了物理层以太网控制(MAC+PHY)、内存管理等功能,完成了一整套硬件化的以太网解决方案。该方案的连接示意图如下图所示:
在这里插入图片描述
移植讲解与tcp/udp实现看下面两篇博客:
CH395Q驱动库移植以太网通信之UDP/TCP

内容持续更新中…

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐大队队长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值