C
文章平均质量分 91
wenchm
喜欢读书
展开
-
细说STM32单片机通用定时器使用输出比较功能生成PWM波的方法
自动定义表示定时器TIM2的外设对象变量htim2,在函数MX_TIM2_Init()中,设置htim2各参数的值之后,调用HAL_TIM_Base Init()进行定时器初始化,调用HAL_TIM_OC_Init() 进行输出比较初始化,然后使用TIM_OC_InitTypeDef类型的变量sConfigOC设置输出比较通道的参数,再调用函数HAL_TIM_OC_ConfigChannel()对TIM2的CH1进行输出比较配置。HSE选择外部晶振,24MHZ,APB1 = APB2 = 170MHz;原创 2024-09-15 17:26:58 · 925 阅读 · 0 评论 -
细说STM32F407通用定时器的基础知识
通用定时器的区别主要在于计数器的位数、捕获/比较通道的个数不同。通用定时器具有以下特性。16位或32位自动重载计数器。16位可编程预分频器,分频系数为1~65536。分频系数可在运行时修改。有1、2或4个独立通道,可用于:输入捕获、输出比较、 PWM生成(边沿对齐或中心对齐)、单脉冲模式输出。可使用外部信号控制定时器,可实现多个定时器互连的同步电路。发生如下事件时产生中断或DMA请求:(1)更新——计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发);原创 2024-09-12 16:35:17 · 794 阅读 · 0 评论 -
细说STM32F407基础定时器的基础知识
STM32F407有2个高级控制定时器、10个通用定时器和2个基础定时器。基础定时器功能简单,只能用于定时,通用定时器和高级控制定时器还具有输入捕获、输出比较、PWM输出等功能。这些定时器挂在APB2或APB1总线上,所以它们的最高工作频率不一样,这些定时器的计数器有16位的,也有32位的。定时器类型定时器计数器长度计数类型DMA请求生成捕获比较通道数所在总线基础TIM6TIM716位递增有0APB1通用TIM2TIM53 2位递增、递减、递增递减有4。原创 2024-09-10 10:18:33 · 1107 阅读 · 0 评论 -
细说MCU基础定时器连续中断和单次中断的实现方法
本文旨在叙述ST单片机STM32G474RCT6的基础定时器的中断的实现方法。原创 2024-08-09 11:03:52 · 784 阅读 · 0 评论 -
细说MCU检测按键输入的外部中断和修改HAL_GPIO_EXTI_IRQHandler() 的实现方法
本文使用的硬件板是ST的开发板NUCLEO-G474RE,板上MCU型号为STM32G474RET6。并按照资源提示设计制造了扩展IO板,有需要此扩展板的留言联系我。本例设计目的及其功能和操作流程如下。产生EXTI0软中断LED1PB11推挽输出High上拉LED2PB12推挽输出High上拉KeyRightK1PA0EXTI0输入上拉KeyDownK2PA1EXTI1输入上拉KeyLeftK3PA6EXTI[9:5]输入上拉Ke。原创 2024-08-08 08:30:00 · 1044 阅读 · 0 评论 -
细说工程师如何编写有使用价值的单片机程序(以GPIO为例)
函数ScanPressedKey()用轮询方式检测按键输入,也就是用函数HAL_GPIO_ReadPin()不断地读取4个按键引脚的输入,如果某个按键引脚的输入信号有效,就表示检测到按键输入了, 将这个按键的枚举值作为函数返回值。LED和蜂鸣器的操作定义为宏函数,例如,LED1_Toggle()使LED1输出翻转,LED1_ON(),点亮LED1,LED1_OFF()熄灭LED1。配置PA4,GPIO OUTPUT,默认Low Level,PP,PullUp,High Speed,标识为Buzzer;原创 2024-08-06 16:39:32 · 712 阅读 · 0 评论 -
细说MCU构建两路包含ADC和DAC的测量系统的方法
用MATLAB语句产生两路DAC波形数据:一路为50 Hz正弦信号,另外一路为带三次谐波的正弦信号。一个周期的数据点数为200。%信号幅值N = 200;%一个周期内的数据点数Ph = 0;%信号1初始相位%正弦波带谐波的MATLAB语句详见本文的参考文件。由于要用到按键B1切换串口发送的数据,所以在中断中设置了一个标志变量SignalFlag (数据类型可定义为uint8_t)。该变量初始为0,每按一次加1,按两次后又赋值为0。原创 2024-08-01 08:30:00 · 1209 阅读 · 0 评论 -
细说MCU构建包含ADC和DAC的测量系统的方法
DAC所用的波形数据在数组SineWaveDataPh0中,使用MATLAB语句产生200个带高次谐波的数据点。由于DMA传递完规定数目的ADC采样值后会触发回调函数HAL_ADC_ConvCpltCallback()的执行,所以可在该回调函数中将ADC的采样值通过串口发送出来。原创 2024-08-01 08:30:00 · 742 阅读 · 0 评论 -
细说MCU的DAC改变输出信号频率的方法
前面配置定时器TIM3的参数时,计数器的周期设为169,由于系统时钟频率为170 MHz,所以定时器的Update Event频率为170MHz/((0+1)*(169+1))=1 MHz。由于倍数比较高,单纯修改计数器的周期值无法实现,所以需要先将定时器时钟的预分频因子修改为169,也就是设置定时器的时钟频率为1 MHz,然后将计数器的周期修改为399,则定时器Update Event的频率为170MHz/((169+1)*(399+1)) = 2.5 kHz。把输出信号的频率由20kHz改为50Hz。原创 2024-07-31 08:30:00 · 661 阅读 · 0 评论 -
细说MCU的DAC输出含谐波的正弦波形信号的方法
本项目依赖的软件和硬件工程参考本文作者写的文章:细说MCU的DAC1和DAC2各自输出一通道模拟信号的方法-CSDN博客要输出含谐波的正弦波形,关键是生成一个周期的含谐波信息的波形数据。原创 2024-07-31 08:30:00 · 597 阅读 · 0 评论 -
细说MCU的DAC1和DAC2各自输出一通道模拟信号的方法
将外设 (Peripheral)选择为按字(Word)的方式,存储器(Memory)的数据宽度选择为按半字(Half Word)的方式。将外设 (Peripheral)选择为按字(Word)的方式,存储器(Memory)的数据宽度选择为按半字(Half Word)的方式。在DAC1通道的设置区,先将它们的输出缓冲(Output Buffer)禁止 (也可以保持使能),随后分别将它们的Trigger参数选择为Timer3 Trigger Out event。在初始化代码中加入启动定时器、启动DAC的代码。原创 2024-07-30 13:30:32 · 741 阅读 · 0 评论 -
细说MCU的DAC1实现两个通道同时输出的方法
存储波形数据的数组DualSineWaveData在这里这个数组要定义成32位的,每个数据点包含两个16位的数,分别传递给DAC1的CH1和CH2。本例给出一个示例波形数据是两个正弦波,其中一个的幅值是另一个的一半。将上述数组DualSineWaveData定义为全局变量,放到主函数的注释对中。原创 2024-07-30 11:01:11 · 635 阅读 · 0 评论 -
细说MCU用自带的波形发生器实现DAC输出的方法
在TIM3模式和配置界面中,先将模式(Mode)的时钟源(Clock Source)选择为内部时钟(Internal Clock);在定时器设置(Counter Settings)区,将预分频因子(Prescaler)设置为0,计数器周期(Counter Period)设置为169。开启定时器的初始化语句是HAL_TIM_Base_Start(),初始化三角波发生器的语句是HAL_DACEx_TriangleWaveGenerate()和启动DAC的语句HAL_ DAC_Start()。原创 2024-07-26 15:20:59 · 724 阅读 · 0 评论 -
细说MCU用DMA改变DAC输出信号频率和改善输出波形质量的方法
如果VREF为3.3 V,在开启缓冲后,虽然数据输出寄存器数据在0~4095范内变化,但DAC的真实输出会在0.2~3.1 V之间。前面例子所给的数据中,送给数据输寄存器的最大值为4090,最小值为5,所以在峰值处会有饱和现象。虽然定时器的更新频率保持为1 MHz,即DMA会1us传递一个数据到DAC的数据输出寄存器;但由于数据点数由50增加到200,所以传递一个完整周期的数据所需的时间,也就由原来的50us增加至200us。此时,再用示波器查看PA4引脚上的波形,得到的该正弦波的频率为20 kHz。原创 2024-07-25 17:07:23 · 1268 阅读 · 0 评论 -
细说MCU用DMA实现DAC输出的方法
这里给出的SineWaveData,长度为DAC_BUFFER_SIZE(在前面已将其定义为50)。这个数组中的数据,实际是一个周期的正弦信号数据;也就是说,将一个周期的正弦波形,用50个数据点来表示。原创 2024-07-25 16:20:57 · 856 阅读 · 0 评论 -
细说MCU用定时器控制单路DAC模块设计和输出锯齿波的实现方法
硬件配置完成后,在代码中实要做的只有两步:一是用库函数HAL_DAC_Start()启动DAC,二是用函数HAL_DACValue()给DAC的数据寄存器赋值。系统时钟为170MHz时,计数器的计数周期为(169+1)(9+1)/(170*10^6)=10us,对应的频率为0.1MHz。本例依然是在初始化阶段启动DAC,即函数HAL_DAC_Start()放置的位置不变,而将给DAC的数据寄存器赋值的语句放置到定时器的中断中,从而实现用定时器中断控制DAC的输出频率。使能TIM3的中断,优先级设置为0;原创 2024-07-22 16:38:02 · 739 阅读 · 0 评论 -
细说MCU用单路DAC模块设计和输出锯齿波的实现方法
不过,如果开启了DAC的缓冲(Buffer),输出的电压最小值不会为0,最大值也不会是VREF,而是会在0.2 V~VREF-0.2 V之间。DAC模块从MCU引脚上最终输出的电压(VDAC),与输入到它的数据输出寄存器中的数值有关。由于STM32G474RE中的DAC为12位,也就是说,当数据寄存器中的值为4095时,DAC会输出最大电压值,但这个最大值具体是几伏,还与MCU的参考电压(VREF)有关。DAC启动之后,可以在while(1)中给其数据寄存器赋值,这样就可以通过它输出所需要的模拟电压信号。原创 2024-07-20 17:00:56 · 916 阅读 · 0 评论 -
细说MCU用DMA控制ADC采样和串口传送的实现方法
首先定义存储ADC采样结果的数组,本例中用数组变量ADC1ConvertedData。//信号源。原创 2024-07-19 17:10:16 · 1339 阅读 · 0 评论 -
细说MCU用定时器控制ADC采样频率的实现方法并通过Simulink查看串口输出波形
本文作者的文章 细说MCU用定时器控制ADC采样频率的实现方法-CSDN博客中说到了一种用定时器控制ADC采样频率的实现方法,并通过串口调试助手把串口接收到的数据输出到计算机显示器。在这篇文章中,利用同样的硬件设置,作者通过MATLAB中的Simulink建立一个串口接收模型,然后和.ioc工程的串口握手通讯。接收并在Time scope控件上显示串口数据波形在display控件上显示数据。原创 2024-07-18 15:44:29 · 900 阅读 · 0 评论 -
细说MCU用定时器控制ADC采样频率的实现方法
/信号源//串口打印return ch;原创 2024-07-12 17:13:48 · 1144 阅读 · 0 评论 -
细说MCU的ADC模块单通道连续采样的实现方法
TIM3中断定义一个数组,用于存储A/D转换结果。每执行一次回调函数,就将此次A/D转结果存入数组,直到存满。随后,在主程序中,通过串口送出数组中存储的数据。其中,数组长度ADC_CONVERTED_DATA_BUFFER_SIZE定义到main.h中。原创 2024-07-05 10:55:16 · 936 阅读 · 0 评论 -
细说MCU的ADC模块单通道单次采样的实现方法
由于希望在产生按键中断时,启动ADC采样,所以,需要重定义外部中断EXTI的回调函数。这个回调函数可以写在main.c文件后面的一个注释对中。原创 2024-06-22 17:12:52 · 1492 阅读 · 0 评论 -
细说MCU定时器模块的输入捕捉功能的实现方法
由于要记录两次发生捕捉中断时刻计数器的值,所以需要定义四个变量:存放两次计数值及它们之间的差值的变量,以及一个计数标志用的变量。将这些变量定义为全局变量,放置到main.c中的一个注释对中。//存放第一个计数�??//存放第二个计数�??//存放两个计数值之�?//计数标志这个函数在stm32g4xx_hal_tim.c中是以弱函数的形式被定义的,实际是一个空函数,所以要在main.c中重新定义它。/*记录第一个计数值 *//*记录第二个计数值 *//*计算两次计数值之值 */原创 2024-06-22 10:52:29 · 1046 阅读 · 0 评论 -
细说MCU输出互补型PWM波形时设置死区时间的作用
因为实际开关的动作(导通和关断)是需要时间的,虽然互补型PWM在理论上能保证两路信号完全互补,但从信号发出到开关实际动作,还是需要一定时间的。死区时间的设置,就可以避免两个开关同时导通的可能性。由于没有设置计数器的预分频因子,所以两次计数的时间间隔为(1/170)μs,这个100所代表的时间就是100个定时器的时钟周期,约为0.588 ns。在截图中,可以清楚地看到,在PA8(通道1)由低电平变为高电平之前,PA7(通道2就已经由高电平变为了低电平,这两个跳变沿之间的时间就是死区时间。原创 2024-06-19 13:01:04 · 966 阅读 · 0 评论 -
细说MCU输出互补型PWM波形的实现方法
随后,还需要在主程序中的初始化代码部分调用库函数,开启定时器中断、使能PWM。启动定时器中断还需要用库函数HAL_TIM_Base_Start_IT()。调用该函数的语句如下:其中,htim1为TIM1的句柄。原创 2024-06-19 08:30:00 · 1757 阅读 · 0 评论 -
细说MCU输出两路PWM波形及改变占空比的实现方法
目录一、硬件及工程 二、建立工程三、代码修改四、下载运行五、改变PWM波形占空比1、定义两个全局变量2、启动定时器3、重写TIM3中断回调函数六、下载并运行 文章依赖的硬件及工程配置参考本文作者的其他文章:细说ARM MCU的串口接收数据的实现过程-CSDN博客 https://wenchm.blog.csdn.net/article/details/139541112 通过PB4输出配置一个通道TIM3_CH1、通过PB5输出配置一个通道TIM3_CH2。用示波器进行观察PB4原创 2024-06-18 10:31:38 · 1354 阅读 · 0 评论 -
细说MCU通过定时器输出PWM波形的实现方法
* 定时器中断回调函数操纵GPIO PC3输出波形 */原创 2024-06-18 08:30:00 · 945 阅读 · 0 评论 -
细说MCU定时器中断的实现方法
在main.c中重新定义回调函数HAL_TIM_PeriodElapsedCallback()。在其中让PA5的输出状态翻转。本例中,定时器的预分频因子(Prescaler)和计数器周期(Counter Period)分别置为999和16999,定时器的时钟频率为170 MHz,最终TIM3中断的周期为(999+1)/(170×10⁶)×(16999+1)=0.1(s),即频率为10 Hz。原创 2024-06-13 08:30:00 · 1197 阅读 · 0 评论 -
细说MCU串口函数及使用printf函数实现串口发送数据的方法
如果想查看具体收到的是什么数据,可以按一下NUCLEO-G474RE板上的B1键,在串口助手上就会显示所接收到的数据。连续发送4次数据53 10 45 ,会收到4次数据正确的消息“Everything is OK” ,并不是程序写错了,而是程序没写判断数据的对错,程序只是判断数据是否准备妥当了。在上面putchar函数的定义中,串口发送函数使用的是库函数HAL_UART_Transmit(),每次发送1字节的数据。按下B1键,看看MCU接收到了什么数据并显示到串口助手上,按一下B1显示一次。原创 2024-06-12 11:28:26 · 1250 阅读 · 0 评论 -
细说MCU修改回调函数调用模式的方法
在本文作者的文章中:细说ARM MCU的串口发送数据的实现过程-CSDN博客串口每接收到1字节的数据,就调用一次回调函数。实际上,可以通过修改参数,在接收了一定长度的数据之后再调用回调函数。下面尝试当串口接收到3字节数据后再调用一次回调函数。原创 2024-06-12 09:21:06 · 751 阅读 · 0 评论 -
细说ARM MCU的串口发送数据的实现过程
前面的文章介绍了用串口的接收中断来接收数据,本文介绍通过串口从MCU向外发送数据。原创 2024-06-11 15:27:57 · 611 阅读 · 0 评论 -
细说ARM MCU的串口接收数据的实现过程
重定义串口中断接收的回调函数HAL_UART_RxCpltCallback()。这个函数已经在stm32g4xx_ hal_uart.c中有定义,只不过被定义为弱函数,实际就是一个空函数。需要重写它。与写EXTI的回调函数类似,也将该函数写在main.c中。串口有数据送来,会执行中断服务函数USART2_IRQHandler(),然后该函数又会调用函数HAL_UART_IRQHandler()。原创 2024-06-11 14:22:17 · 1502 阅读 · 0 评论 -
细说ARM MCU中的HAL_GPIO_Init()函数的实现过程
继续上一篇文章,分析HAL_GPIO_Init函数是如何实现的,该函数的定义在stm32g4xx_hal _gpio.c文件中。原创 2024-06-02 08:00:00 · 715 阅读 · 0 评论 -
细说ARM MCU中的MX_GPIO_Init()函数的实现过程
本文中使用ST的开发板NUCLEO-G474RE,板上MCU型号为STM32G474RET6。配套的扩展板:实例中当开发板上的按键B1被按下时,PC13引脚被上拉至高电平VDD,不按下时,PC13下拉至低电平GND。用按键B1控制板上的LD2灯的亮灭,当PA5输出高电平时LD2亮,否则灯灭。原创 2024-05-30 11:25:02 · 846 阅读 · 0 评论 -
几种在ARM MCU上控制流水灯的方法
对于初学者,在ARM单片机上控制流水灯的亮灭是必经之路。控制流水灯的亮灭有很多方法,比如8个LED,可以控制8灯同时亮、灭;可以控制8灯依次亮、灭;可以控制8灯依次亮、灭,然后反方向再依次亮、灭;可以控制8灯依次亮、灭;可以控制8灯依次点亮全部、然后依次熄灭全部;原创 2024-06-02 08:00:00 · 698 阅读 · 0 评论 -
优化C/C++代码:内联函数与宏展开在处理大量case表达式时的应用
使用内联函数或者宏展开是可以优化C/C++代码执行效率的。减少函数调用的开销。原创 2024-06-01 08:00:00 · 300 阅读 · 0 评论 -
优化C/C++代码:处理大量case表达式时的优化策略
当 C 语言项目中的 switch 语句包含多达 300 多个 case,就可能导致性能问题,特别是如果每个 case 的逻辑相对简单且执行时间较短。在这种情况下,大部分时间可能被花在了通过跳转表(jump table)来找到相应的 case 执行代码上。原创 2024-06-01 08:00:00 · 507 阅读 · 0 评论 -
细说常见的原子操作 (CAS)和(LL/SC)及常与其一起使用的仲裁(Arbitration)
例如,它可能导致“ABA”问题,即一个值从 A 改为 B,然后又改回 A,尽管这个值变化了,但由于 CAS 只比较是否与期望值相等,因此可能会错过这种变化。例如,在基于锁的仲裁中,原子的锁获取和释放操作可以确保只有一个线程能够持有锁,从而保证资源的独占使用。在某些情况下,这些指令可能会被编译器或运行时环境转换为其他形式的原子操作,以便在不支持LL/SC的硬件上执行。所以,虽然仲裁不是一个直接的原子操作,但在设计高并发和分布式系统时,它是确保线程安全和正确性的关键机制之一,而原子操作则是其实现的基础工具。原创 2024-04-29 15:59:19 · 985 阅读 · 2 评论 -
STM32H745BIT6上的ARM Cortex-M7和Cortex-M4核心共享SRAM4中的数据的方法
这只是一个简化的例子,只是提供了一种解决问题的思路。在实际应用中需要考虑更多的细节,比如错误处理、同步机制的选择(信号量、邮箱、共享变量等)、中断处理以及性能优化等。此外,更需要确保两个核心的时钟和外设访问控制正确配置,以便能够正确地访问共享SRAM。在具体实现时,还需要参考STM32H7xx的参考手册和HAL库提供的API来完成相应的配置和操作。原创 2024-04-29 09:54:55 · 1650 阅读 · 0 评论 -
细说HAL_GPIO_WritePin()函数写操作BSRR和BRR端口寄存器的原理
第一句define宏定义中的(void)0U,是空语句的表达式。将assert_param(expr)定义为:如果表达式expr真,就是空语句(void)0U;如果表达式expr假,则为assert_failed()函数。define宏定义后,就是对assert_failed()的声明。如果USE_FULL_ASSERT未定义过,则会编译#else中的内容,就是用define宏定义直接将assert_param(expr)定义为空语句(void)0U。原创 2024-04-28 16:15:54 · 3524 阅读 · 0 评论