今天还在做 STM32 DAC Function generator 唉~ 毕竟单片机的机能有限,做函数发生器略显吃力,不过STM32自带DAC能实现 100KHz 40样点正弦信号 确实已经相当强悍了。DAC 使用DMA + 定时器触发转换。
而今天的问题在于 做这个Function generator时编写的一套简单串口终端界面出现了一个令我百思不得其解小BUG.....
输入部分:
USART2_Puts(star[wav_mode-1]);
USART2_Puts(" Enter Frequency: ");
while(Uart2_Get_Data!=0x0d&&nde<6)
{
if(Uart2_Get_Flag)
{
Uart2_Get_Flag=0;
tmp[nde++]=Uart2_Get_Data;
if(tmp[nde-1]<48||tmp[nde-1]>57)nde--;
else USART2_Putc(tmp[nde-1]);
//Uart2_Get_Flag=0;
//Uart2_Get_Data=60;
}
中断:
if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
Uart2_Get_Data=USART_ReceiveData(USART2);
Uart2_Get_Flag=1;
}
开始的时候 Uart2_Get_Data 的类型是 U8 以前也是这么做的 没有问题的,但偏偏这次有问题 就是在输入的时候
Enter Frequency: 后面的数字总是重复的 一般重复两次比如图上的2244 而且有时单步仿真的时候问题又消失了。
代码不断地改 越改越乱~~~
突然注意到 用SysTick_Handler 延时的中断里 数据的类型被 volatile 修饰过,问题可能在这
马上..........
volatile u8 Uart2_Get_Flag; //串口2接收到数据
volatile u8 Uart2_Get_Data; //串口2接收的数据
问题解决了~~!!
没有用volatile关键字声明的变量在被访问的时候可能直接从cpu的寄存器中取值(因为之前i被访问过,也就是说之前就从内存中取出i的值保存到某个寄存器中),之所以直接从寄存器中取值,而不去内存中取值,是因为编译器优化代码的结果(访问cpu寄存器比访问ram快)。
然而在 串口中断里 Uart2_Get_Data 的值可能被“以外修改”而CPU寄存器的值没变所以出问题了。volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:中断、system、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
按理说凡是在中断里等频繁更新而外部频繁调用的值都应当用volatile进行修饰 .
关键字:STM32 代码 类型修饰符 volatile
引用地址:
STM32 代码中类型修饰符 volatile 的作用
推荐阅读最新更新时间:2024-03-16 15:13
基于MDK编译器 STM32与12864液晶显示程序 和电路连接
里附上的是主程序部分和电路连接 这里用的12864液晶是5v的,电路链接部分 RS PE2 RW PE4 EN PE6 15口PSB串并 PE3 #include stm32f10x.h GPIO_InitTypeDef GPIO_InitStructure; #define RS_SET GPIO_SetBits(GPIOE, GPIO_Pin_2) #define RS_CLR GPIO_ResetBits(GPIOE, GPIO_Pin_2) #define RW_SET GPIO_SetBits(GPIOE, GPIO_Pin_4) #define RW_CLR GPIO_Re
[单片机]
STM32移植LWIP官方demo
本文使用的IDE是IAR7.2,考虑到很多很使用Keil,本文也有keil版本的说明 1、硬件说明 主控:STM32F207VCT6,100管脚的封装 网络PHY芯片:RTL8201EL,48管脚封装,34和35管脚下拉,也就是芯片地址:0 使用的网络接口:MII接口 2、移植步骤 2.1、修改IAR配置文件 修改芯片设置(其实不用修改) 硬件使用的是SWD模式 2.2、修改网络PHY地址 在stm32f2x7_eth_bsp.h文件中 2.3、修改硬件IO 在stm32f2x7_eth_bsp.c中 2.4、屏蔽无用的东西和修改IP 在main.h中 修改IP地址(以读者本机I
[单片机]
STM32系统时钟的小知识
什么是时钟? 时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。 为什么 STM32 要有多个时钟源呢? STM32本身十分复杂,外设非常多 但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费 并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的
[单片机]
STM32 中的 assert_param 函数
我们在学STM32的时候函数assert_param出现的几率非常大,上网搜索一下,网上一般解释断言机制,做为程序开发调试阶段时使用。下面我就谈一下我对这些应用的看法,学习东西抱着知其然也要知其所以然。 4 断言机制函数assert_param 我们在分析库函数的时候,几乎每一个函数的原型有这个函数assert_param();下面以assert_param(IS_GPIO_ALL_PERIPH(GPIOx));为例说一下我的理解,函数的参数IS_GPIO_ALL_PERIPH(GPIOx),我们可以寻找到原型 #define IS_GPIO_ALL_PERIPH(PERIPH) (((*(uint32_t*)&(PERIPH))
[单片机]
STM32单片机为什么要中断
STM32中断主题: 1什么是中断 暂停原先的程序或事情,执行另外一些程序或事情,执行完成后返回原来的程序。 2为什么要中断 因为另一些程序或事情比你原先正在做的事情要重要,或者这些突发事情你是无法控制它的来临的。 3 中断的分类 按不同方法进行分类 3.1 内部中断,外部中断 (向量表中灰色为内部) 3.2 可设置中断,固化中断 3.3 中断向量表 (cl级别的芯片有10个内部 ,0~67个外部,一些没用到,其中通用化 中断编号0~17,个性化中断编号18~67) 3.4 优先级别 (由主优先级和从优先级组成,主从优先级可以通过4个位进行设置) 4 中断的组成 具体中断的名称 中断的地址 用来保存一条跳转指令,跳到哪里去
[单片机]
STM32 SPI Flash DFU
这次讲的是将程序、图片或其他文件下载到SPI Flash中。我使用的是W25X16的SPI Flash,他共有2MB空间,2个Block,512ge Sector,8096个Page。由于SPI Flash不能直接跑程序,我们从接口就知道了。 接下去我们就来讲讲怎么编写SPI flash的升级功能。这次的工程是基于之前的Internal Flash修改而来的。修改的部分主要在USB_User组里: 我只将改改的部分。 hw_config.c、usb_istr.c、usb_prop.c、usb_pwr.c这介个文件没有什么还修改的。usb_desc.c文件需要修改下接口字符串描述符,由于我们的SPI Flash空间2M,所以我们将
[单片机]
STM32的GPIO工作方式
GPIO支持4种输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)。同时,GPIO还支持三种最大翻转速度(2MHz、10MHz、50MHz)。 每个I/O口可以自由编程,但I/O口寄存器必须按32位字被访问。 GPIO_Mode_AIN 模拟输入 GPIO_Mode_IN_FLOATING 浮空输入 GPIO_Mode_IPD 下拉输入 GPIO_Mode_IPU 上拉输入 GPIO_Mode_Out_OD 开漏输出 GPIO_Mode_Out_PP 推挽输出 GPIO_Mode_AF_OD 复用开漏输出 GPIO_Mode_AF_PP 复用推挽输
[单片机]
使用STM32点亮一颗LED实验
本次实验系统环境 Matlab版本: 2021b 系统环境 :Win10专业版 模型与原理图 simulink模型如图5.1所示,实验现象PB8以0.5S周期反转,PB9以1S周期翻转闪烁,本次实验电路原理如图5.2所示,实验所使用的下载器为STLINK 2V1版本,下载器自带一个串口,完整实验电路板如图5.3所示 图5.1 两颗LED闪烁simulink模型 图5.2 LED闪烁电路图 图5.3 实验开发板 基础模型介绍与分析 “Digital Write”模型用于控制I/O口作为普通输出用,双击模型可更改引脚编号,如图5.4所示其引脚对应STM32的PB8端口,例如想使用PA5引脚时,可通过将其改为“PA_
[单片机]