stm32学习笔记
1.软件调试相关
1.1有关调试器/下载器
- JTAG: 是仿真使用的协议.
- J-Link是德国SEGGER公司做的仿真器.
- ST-LINK是ST公司做的专门针对STM8和STM32系列芯片的仿真器.
1.2有关芯片资源
STM32F103的可用代码区 = 512KB
STM32F103的可用RAM区 = 64KB
STM32F407的可用代码区 = 1024KB
STM32F407的可用RAM区 = 192KB
STM32F103C8T6 晶振:8mhz(使用核心板时需要在MDK-target配置)
STM32F103ZE 晶振:12mhz
1.3有关MDK配置
1.3.1工程跨芯片移植
1.4MDK报错总结
1.向MDK添加文件头上有钥匙的解决办法:把文件属性的只读给去掉
2.这个问题已经遇到过很多次了,通常自己在源码的模板上自己加模块写程序的时候,会报错
…\OBJ\OLED.axf: Error: L6218E: Undefined symbol TIM_ClearITPendingBit (referred from tpad.o).
解决办法:在hardware目录下面添加stm32f10x_tim.c和stm32f10x_tim.h
3.要读取RTC_CNT寄存器中的时间,首先要向寄存器bkp里面写入不一样的值,才能设定时间。
BKP_WriteBackupRegister(BKP_DR1,0x0505)
这句很重要,否则无法修改时间,但是一旦修改完成,要把它注释掉!
u8 RTC_Init(void)
{
//检查是不是第一次配置时钟
u8 temp=0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
***BKP_WriteBackupRegister(BKP_DR1,0x0505);***
if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
{
BKP_DeInit(); //复位备份区域
RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250) //检查指定的RCC标志位设置与否,等待低速晶振就绪
{
temp++;
delay_ms(10);
}
if(temp>=250)return 1;//初始化时钟失败,晶振有问题
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_WaitForSynchro(); //等待RTC寄存器同步
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_EnterConfigMode();/// 允许配置
RTC_SetPrescaler(32767); //设置RTC预分频的值
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_Set(2020,8,10,21,48,55); //设置时间
RTC_ExitConfigMode(); //退出配置模式
BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据
}
else//系统继续计时
{
RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
}
RTC_NVIC_Config();//RCT中断分组设置
RTC_Get();//更新时间
return 0; //ok
}
4.如果一个工程要同时使用lcd和oled,里面的字库头文件会重定义,解决方法是其中一个头文件定义的时候加static全局变量
5.Undefined symbol xxx (referred from xxx.o)
- 检查.c目录下是否包含正确文件
- 如果还是不行,在STM32F10x_FWLib中添加相关文件(正点)
6.
加入#include “stdio.h”即可
2.常用外设相关
2.1有关LCD
2.2有关ADC
2.2.1ADC简介
STM32F1和F4系列有3个ADC,精度为12位,每个ADC最多有16个外部通道。其中ADC1和ADC2都有16个外部通道,ADC3一般有8个外部通道,各通道的A/D转换可以单次、连续、扫描或间断执行,ADC转换的结果可以左对齐或右对齐储存在16位数据寄存器中。
对于F1: ADC的输入时钟不得超过14MHz,否则将导致结果准确度下降。
对于F4: ADC的输入时钟不得超过36MHZ,否则将导致结果准确度下降。
2.2.2规则通道和注入通道
【规则通道】最平常的通道、也是最常用的通道,平时的ADC转换都是用规则通道实现的。
【注入通道】注入通道可以在规则通道转换时,强行插入转换,相当于一个“中断通道”吧。当有注入通道需要转换时,规则通道的转换会停止,优先执行注入通道的转换,当注入通道的转换执行完毕后,再回到之前规则通道进行转换。
2.2.3转换顺序
多个通道的使用顺序分为俩种情况:规则通道的转换顺序和注入通道的转换顺序。
规则通道中的转换顺序由三个寄存器控制:SQR1、SQR2、SQR3,它们都是32位寄存器。SQR寄存器控制着转换通道的数目和转换顺序,只要在对应的寄存器位SQx中写入相应的通道,这个通道就是第x个转换。对应关系如下图所示:
同理,注入通道的转换也是通过注入寄存器来控制,只不过只有一个JSQR寄存器来控制,控制关系如下:
2.2.4 F1/4ADC通道引脚关系
2.2.5注意事项
- 用作ADC采集的IO必须没有复用,否则采集电压会有影响
- ADC1 对应 DMA1通道1,ADC3对应DMA2通道5,ADC2没有DMA功能
推荐一篇文章,讲的非常非常详细:
stm32ADC详解
2.3有关中断
stm32有16级优先级
2.3.1中断优先级及其分组
- 中断优先级:高优先级的中断(优先级编号小)先得到响应
- 中断嵌套:高优先级的中断可以抢占低优先级的中断
- 有固定优先级的中断:复位、NMI(不可屏蔽中断)、HardFault(出现硬件错误)
- 中断优先级分组:如下图,8位优先级配置寄存器stm32只使用了高4位,所以抢占/响应优先级有5种分法。
FreeRTOS配置是选择组4.
GUI配置选择组4
总结:多个中断发生时,先看抢占优先级高低,抢占等级相同的看触发先后时间,先后顺序一样(同时)的看响应等级。
2.3.2重要寄存器
- 有关中断屏蔽的特殊寄存器
PRIMASK寄存器:用于禁止除 NMI 和 HardFalut 外的所有异常和中断
FAULTMASK 寄存器:比 PRIMASK 更狠, 它可以连 HardFault 都屏蔽掉
BASEPRI 寄存器:在有些场合需要对中断屏蔽进行更细腻的控制, 比如只屏蔽优先级低于某一个阈值的中断
2.3.3外部中断
STM32F103的外部中断一共有19个,每个IO口都可以作为外部中断的输入。
以下是中断线和外部中断的对应关系:
线 0~15:对应外部 IO 口的输入中断(映射关系:GPIOX_PIN0这七个IO对应中断线0)
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件。
查阅F1和F4的启动文件可以发现对应的中断入口函数:
EXTI0_IRQHandler ; EXTI Line 0
EXTI1_IRQHandler ; EXTI Line 1
EXTI2_IRQHandler ; EXTI Line 2
EXTI3_IRQHandler ; EXTI Line 3
EXTI4_IRQHandler ; EXTI Line 4
EXTI9_5_IRQHandler ; External Line[9:5]s
EXTI15_10_IRQHandler ; External Line[15:10]s
外部中断配置结构体:
typedef struct
{
uint32_t EXTI_Line;//中断线标号
EXTIMode_TypeDef EXTI_Mode;//中断模式,可选中断触发或事件触发
EXTITrigger_TypeDef EXTI_Trigger;//触发方式,可选上升沿触发或下降沿触发或任意电平触发
FunctionalState EXTI_LineCmd;//中断线使能
}EXTI_InitTypeDef
2.3.4 注意点
1.在中断服务函数里面要注意清除这一条中断线上的标志位!
2.检测上升沿要配置成下拉模式,下降沿要上拉模式。
3.中断服务程序里,不能调用printf,malloc 函数。
2.4有关看门狗
作用:避免mcu程序跑飞,如果一段时间没有收到喂狗信号,则使mcu自动复位
驱动时钟:单片机内部低速时钟,30khz–60khz,RC时钟所以频率不稳
2.5有关PWM及定时器
2.5.1定时器简介
定时器的分类:高级定时器、通用定时器、基本定时器,这3类定时器的功能各不相同。
STM32F103有8个定时器。
名称 | 位数 | 计数模式 | DMA请求 | 捕获/比较通道 | 互补输出 | 特殊应用场景 |
---|---|---|---|---|---|---|
高级定时器(TIM1/8) | 16 | 向上、向下、向上/下 | 可以 | 4 | 有 | 带死区控制和紧急刹车,可应用于PWM控制 |
通用定时器(TIM2-5) | 16 | 向上、向下、向上/下 | 可以 | 4 | 无 | 定时器计数,PWM输出,输入捕获,输出比较 |
基本定时器(TIM6/7) | 16 | 向上、向下、向上/下 | 可以 | 4 | 无 | 主要应用于驱动DAC |
STM32F4XX有14个定时器。 | ||||||
名称 | 位数 | 计数模式 | DMA请求 | 捕获/比较通道 | 互补输出 | 特殊应用场景 |
– | – | – | – | – | – | – |
高级定时器(TIM1/8) | 16 | 向上、向下、向上/下 | 可以 | 4 | 有 | 带死区控制和紧急刹车,可应用于PWM控制 |
通用定时器(TIM2/5) | 32 | 向上、向下、向上/下 | 可以 | 4 | 无 | 定时器计数,PWM输出,输入捕获,输出比较 |
通用定时器(TIM3/4) | 16 | 向上、向下、向上/下 | 可以 | 4 | 无 | 定时器计数,PWM输出,输入捕获,输出比较 |
通用定时器(TIM9-14) | 16 | 向上 | 不可以 | 2 | 无 | 定时器计数,PWM输出,输入捕获,输出比较 |
基本定时器(TIM6/7) | 16 | 向上、向下、向上/下 | 可以 | 0 | 无 | 主要应用于驱动DAC |
2.5.2PWM模式以及比较极性确定
模式1:cnt小于比较值的时候为有效电平
模式2:cnt大于比较值的时候为有效电平
有效电平的具体极性要根据结构体中的TIM_OCPolarity来设定
比如输出一个pwm波形,设定越大,脉宽越宽,电压越大,可以参考以下设定
方法一:PWM调制模式1、输出比较模式高
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
方法二:PWM调制模式2、输出比较模式低
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
2.5.3PWM频率以及占空比计算
STM32F1PWM频率计算公式:Fpwm = 72M / ((arr+1)*(psc+1))(单位:Hz)
PWM占空比计算公式:duty circle = CCR / arr(单位:%)
2.5.4PWM配置定时器需要注意的点
1.注意TIMX是高级定时器还是普通定时器,这决定配置APB1/2时钟
RCC_APBxPeriphClockCmd(RCC_APB1Periph_TIMx, ENABLE); //使能定时器5时钟
RCC_APBxPeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE); //使能GPIO外设
2.注意定时器的channel决定了一下这个函数
TIM_OCxInit(TIMx, &TIM_OCInitStructure); //通道x的配置
2.5.5 F1/4定时器引脚分布
2.6有关DMA
2.6.1 STM32F10xDMA
STM32F10x系列芯片最多有2个DMA控制器(DMA2仅存在大容量产品中),DMA1有7个通道。DMA2有5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个DMA请求的优先权。
从外设(TIMx[x=1、2、3、4]、ADC1、SPI1、SPI/I2S2、I2Cx[x=1、2]和USARTx[x=1、2、3])产生的7个请求,通过逻辑或输入到DMA1控制器,这意味着同时只能有一个请求有效。各个通道的DMA1请求一览见下图:
2.6.2 STM32F4xxDMA
【数据流】
每个DMA控制器有8个
数据流,每个数据流都能够提供源
和目标
之间的单向传输链路。
每个DMA控制器可以同时配置多个数据流,但在某一时刻只允许有一个数据流使用DMA控制器。当多个数据流同时请求时,由仲裁器决定哪一个数据流优先使用DMA控制器。
【数据通道】
每个数据流有8个通道,每个通道映射到不同外设,这有利于针对不同的产品配置不同的DMA外设请求。
每个数据流只能配置为映射到一个通道,无法配置为映射到多个通道。即,与数据流不同,每个DMA控制器可以同时配置多个数据流(因为有仲裁器),但每个数据流不能同时配置多个通道(因为只有选择器)。
2.7有关串口
2.7.1 注意事项
1.USART 数据寄存器(USART_DR)只有低 9 位有效,并且第 9 位数据是否有效要取决于USART 控制寄存器 1(USART_CR1)的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M位为 1 表示 9 位数据字长,我们一般使用 8 位数据字长。
2.USART_DR 包含了已发送的数据或者接收到的数据。 USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。
3.TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。
USART_SendData(USART1,cmd[t]);//可以代替printf带来的麻烦配置
4.uart+中断的方式接收数据只能以数据包的格式(0x0d 0x0a)结尾;如果需要接收定长的数据需要配置uart+DMA
具体查看:https://blog.csdn.net/heda3/article/details/80602287
5.串口传输和你接没接引脚没有关系,比如说USART1以PA9作为TXD,以PA10作为RXD,那么IC需要和mcu通信时,IC的RXD应该接PA9。
6.任何两个设备之间串口通信都需要共地
7.如果通过串口下载程序,需要检查PA9和PA10的跳线帽
8.使用USART_SendData发送数据必须加一段延时,典型值10ms,以防止缓冲区溢出。
9.printf函数默认通过串口1发送,如果需要改变,则需要重定向fputc函数
2.7.2 STM32F4xx串口引脚
2.8有关FLASH
【大小】:
STM32F103ZET6 的 FLASH 容量为 512K 字节,主存储器的存储空间被划分为256页,每页2k字节
【注意】:
- 在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作,此期间CPU暂停。
- CPU 运行速度比 FLASH 快得多, STM32F103的 FLASH 最快访问速度≤24Mhz,如果 CPU 频率超过这个速度,那么必须加入等待时间,比如我们一般使用72Mhz的主频,那么FLASH等待周期就必须设置为2,该设置通过FLASH_ACR寄存器设置。
- STM32 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFF),否则无法写入
- FLASH写入数据的地址必须大于本代码所占用FLASH的大小+0X08000000
2.9有关DAC
【精度】:8位或者12位
【简介】:stm32有两个DAC输出通道,互不影响,都可配置使用DMA
【触发方式】:可配置成定时器触发、外部中断触发等等
【注意点】:
- 可以不使用DMA,直接由DAC生成三角波,但是频率不可控,幅值是由宏决定,所以是离散的
- 想要用DAC输出自定义波形,就必须先获取波形采样数据,然后由DMA搬运
- 典型的用DAC输出正弦波,野火给出了频率计算公式:
2.10有关GPIO
2.10.1工作模式
1.模拟输入
模拟信号不经过输入数据寄存器,所以我们无法通过读取输入数据寄存器来获取模拟输入的值,我认为这一点也是非常好理解的,由于输入
数据寄存器中存放的不是0就是1。而模拟输入信号不符合这一要求,所以自然不能放进输入数据寄存器。该输入模式,使我们能够获得外部
的模拟信号。
2.浮空输入
它的输入全然由外部决定,我认为在数据通信中应该能够使用该模式。应为在数据通信中。我们直观的理解就是线路两端连接着发送端
和接收断。他们都须要准确获取对方的信号电平,不须要外界的干预。
3上拉输入
上拉输入就是在输入电路上使用了上拉电阻。这样的模式的优点在于我们什么都不输入时,由于内部上拉电阻的原因,我们的处理器会认为
我们输入了高电平。这就避免了不确定的输入。
这在要求输入电平仅仅要高低两种电平的情况下是非常实用的。
4下拉输入
和上拉输入相似,只是下拉输入时,在外部没有输入时,我们的处理器会认为我们输入了低电平。
5开漏输出
开漏输出,输出端相当于三极管的集电极。所以适合与做电流驱动的应用。要得到高电平。须要上拉电阻才干够。
6推挽输出
推挽输出使用了推挽电路,结合推挽电路的特性。它是由两个MOSFET组成,一个导通的同一时候,另外一个截至,两个MOSFET分别连接
高低电平,所以哪一个导通就会输出相应的电平。推挽电路速度快,输出能力强,直接输出高电平或者低电平。
输出既能够向负载灌电流,也能够从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。
7复用开漏和复用推挽
2.10.2 啥时候需要配置复用呢?
总结为一句话:
挂载在APB1下的内置外设,经过重映射功能,把管脚映射到APB2上!
比如USART是挂载在APB1下的外设,所以使用时可以不用复用
而USART2是挂载在APB2下的内置外设,而GPIO外设挂载在APB1上,所以需要配置复用
3.一些简写名词解释
名词 | 解释 |
---|---|
NVIC | 用于中断管理的嵌套向量中断 |
RCC | Reset and clock control |
FSMC | 可变静态存储控制器 |
4.有关总线
- APB1和APB2
对于F1:
对于F4:
对于stm32f407 168M主频,因为系统初始化SystemInit函数里初始化APB1总线时钟为4分频即42M,所以TIM2TIM7、TIM12TIM14的时钟为APB1的时钟的两倍即84M;APB2总线时钟为2分频即84M,TIM1、TIM8~TIM11的时钟为APB2时钟的两倍即168M。
总线 | 外设 |
---|---|
AHB3 | FSMC |
AHB2 | RNG、HASH、CRYP、DCMI、USB |
AHB1 | DMA、GPIO、CRC、RCC |
APB2 | SPI1、SPI4-6、TIM9-11、EXTI、SYSCFG、ADC、USART1\6、TIM1/8 |
APB1 | DAC、UART4\5\7\8、USART2\3、SPI2\3、TIM2-7、TIM12-14 |
- AHB
stm32F1系列只有一个AHB总线
stm32F4系列有多个AHB总线
移植的时候需要注意
5.有关重映射
STM32F10x系列的MCU复位后,PA13/14/15 & PB3/4默认配置为JTAG功能。有时我们为了充分利用MCU I/O口的资源,会把这些端口设成普通IO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);
// 改变指定管脚的映射 GPIO_Remap_SWJ_JTAGDisable ,JTAG-DP 禁用 + SW-DP 使能
6.有关通信协议
6.1 IIC
简介
两段式串行总线,数据线SDA和时钟线SCL,通常分为硬件iic和软件iic,硬件iic只需要调用封装好的函数即可进行通行,软件iic需要用io模拟iic的时序和外设进行通信。
传输速率
标准模式下可以达到100kb/s,快速模式下可以达到400kb/s
通信方式
半双工(不能同时收发数据,主设备发送数据的时候从设备就不能发)
三类信号
开始信号: SCL 为高电平时, SDA 由高电平向低电平跳变,开始传送数据。
结束信号: SCL 为高电平时, SDA 由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。 CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号, CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
注意点
- SDA的数据只有在SCL为低电平的时候才能改变,SCL为高电平期间数据必须保持稳定。
- 在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)
- 硬件iic可以理解为固件,只能由固定IO驱动,速度比软件模拟快,但是灵活性差
数据帧格式
时序
6.2 SPI
简介
串行外围设备接口
主要应用
读写EEPROM、FLASH、AD转换、数字信号处理和解码
通信方式
高速、全双工、同步
SPI 接口一般使用 4 条线通信:
MISO 主设备数据输入,从设备数据输出。
MOSI 主设备数据输出,从设备数据输入。
SCLK 时钟信号,由主设备产生。
CS 从设备片选信号,由主设备控制。
四种工作方式
如果 CPOL(时钟极性)=1,串行同步时钟的空闲状态为高电平。时钟相位( CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。 SPI 主模块和与之通信的外设备时钟相位和极性应该一致。
时序
7.奇技淫巧及注意点
7.1自己写的oled显示1024个字节的位图的函数(2020.8.13)
void OLED_DrawBMP(const unsigned char BMP[])
{
unsigned int i=0,j=0;
unsigned char x=0,y=0;
unsigned char temp;
for(i=0;i<1024;i++)
{
temp = BMP[i];
for(j=0;j<8;j++)
{
if(temp&0x80)OLED_DrawPoint(x,y,1);
else OLED_DrawPoint(x,y,0);
temp<<=1; //对于每一个字节从高位开始取
y++; //竖写
}
if((i+1)%8==0)
{
y=0;
x++;
}
}
}
7.2有关变量定义
1.要想在main.c里面使用xx.c里面定义的全局变量,必须在xx.h中进行extern申明
2.需要注意的是,如果把变量移动到某个.h文件里,可能会导致有多个.c文件引用该头文件,进而产生多个该变量的定义,所以C语言里有要求,定义变量在.c里,声明在.h里。定义和声明用是否有extern来区分,有extern的是声明,多次出现也无所谓;没有extern的是定义,这个只能出现一次!切记
7.3有关系统裁剪
很多RTOS系统、GUI库都通过条件编译来使系统占用的ROM和RAM减少
#if(条件变量)
void hanshu()
{
}
#end if
7.4 一种将变量转化为const char的方法
char *p;
p = mymalloc(SRAMIN,5);
sprintf((char*)p,"%d",x0);
7.5注意点
- 所有外设在更改其参数之前最好先将其disable,再更改值。比如更改TIM的周期,先要将其失能。
- 再更改某一项外设的结构体的值时,如果申请了该外设的结构体,要一并把其他未更改的值也写上去,否则将会是缺省值
- SystemInit(); 函数在启动文件中自动调用设置好mcu的时钟,不修改的情况下,STM32F4xx的APB1总线时钟为4分频即42M,APB2总线时钟为2分频即84M,所以TIM1、TIM8-TIM11的时钟为APB2时钟的两倍即168M,TIM2-TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍即84M。
- 如果mcu是核心板,确定外部晶振大小,在stm32f10x.h或者stm32f4xx.h中修改HSE_VALUE的值,然后修改system_stm32f10x.c文件中的倍频系数,就可以解决系统时钟错乱的问题。
- 以f1芯片为例,所有的官方头文件的包含设置是在stm32f10x_config.h中
7.6有关嵌入式编程规范
7.7如何修改STM32系统时钟
不同板子的外部晶振一般是不一样的,在keil里面有两个修改点:
1.stm32f4xx或者stm32f10x.h中外部高速时钟的频率
#define HSE_VALUE ((uint32_t)x000000)
2.system_stm32f10x.c或者system_stm32f4xx.c,修改PLL_M参数
#define PLL_M x
8.有关os
8.1 ucosⅢ
8.1.1 注意点
- 如果系统有emwin且带触摸功能,那么,触摸任务的优先级应该是除了必选任务以外最高的,emwin显示优先级应该是最低的
- 中断和任务函数之间的数据传递只能通过全局变量,任务与任务之间的数据传递可以通过消息队列
- FreeRTOS与ucos的优先级不同,前者数字越大优先级越高,后者则相反。