STM32F103VET6——基本定时器中断配置与OLED动态显示实战

python:filecmp --- 文件及目录的比较 阅读详情

1. 定时器基础与STM32F103VET6概述

大家好,今天我们来聊聊STM32F103VET6这款芯片的基本定时器配置,特别是如何结合OLED实现动态显示。STM32F103VET6是ST公司基于ARM Cortex-M3内核的微控制器,内置多个定时器资源,包括基本定时器、通用定时器和高级定时器。基本定时器(如TIM6和TIM7)是其中最基础的定时单元,不具备外部IO功能,但非常适合实现简单的定时中断和计时任务。在实际项目中,我经常用它来生成精确的时间基准,比如周期性采集传感器数据或控制LED闪烁。

STM32F103VET6的定时器时钟源通常来自内部时钟CK_INT,经APB1预分频器后提供。如果APB1预分频系数为1,时钟频率不变;否则频率会翻倍。例如,当APB1预分频系数为2时,PCLK1为36MHz,定时器时钟TIMxCLK则达到72MHz。这个时钟频率通过预分频器PSC进一步分频,得到驱动计数器的实际时钟CK_CNT。计算公式为:CK_CNT = TIMxCLK / (PSC + 1)。通过调整PSC和自动重装载寄存器ARR的值,我们可以灵活设置定时器的周期。

基本定时器的主要功能包括16位自动重装载累加计数器、16位可编程预分频器,以及触发DAC同步电路的能力。它在计数器溢出时产生更新事件,从而触发中断或DMA请求。这些特性使得基本定时器在实时系统中非常有用,尤其是需要精确时间控制的场合。接下来,我会带大家一步步配置定时器中断,并结合OLED显示实时数据。

2. 硬件准备与工程搭建

在开始编码前,我们需要准备好硬件和软件环境。硬件方面,除了STM32F103VET6最小系统板,还需要一块OLED显示屏(常见的是SSD1306驱动的0.96英寸屏),通过I2C或SPI接口与MCU连接。我推荐使用I2C接口,因为它只需两根线(SCL和SDA),节省IO资源。软件上,我们需要安装STM32CubeMX和Keil MDK-ARM(或其他IDE如IAR),以及OLED的驱动库。

首先,用STM32CubeMX创建新工程,选择STM32F103VET6芯片。在Pinout视图中,配置定时器TIM2(因为TIM6和TIM7是基本定时器,无中断输出,这里用TIM2作为通用定时器替代,但配置类似)。设置TIM2为内部时钟源,并启用中断。对于OLED,如果使用I2C,找到I2C1或I2C2接口,配置SCL和SDA引脚(例如PB6和PB7)。在Clock Configuration中,确保系统时钟为72MHz,APB1定时器时钟为72MHz。

在Project Manager中生成代码,选择MDK-ARM工具链。生成后,用Keil打开工程,我们会看到CubeMX生成的初始化代码。接下来,添加OLED驱动文件(通常是一个.c和.h文件)到工程中。在main函数中,初始化OLED和定时器。这里注意,定时器的中断优先级要合理设置,避免与其他中断冲突。我通常使用NVIC_PriorityGroup_2,并将定时器中断优先级设为中等,比如2。

工程搭建完成后,编译下载到板子上。如果一切正常,OLED应该能显示初始内容,定时器也会开始计数。现在,我们来深入定时器的配置细节。

3. 定时器中断配置详解

定时器中断的配置涉及几个关键步骤:时钟使能、时基初始化、中断使能和NVIC设置。以TIM2为例,首先在CubeMX中启用TIM2的时钟(通过RCC设置)。在代码中,我们需要手动配置时基结构体。以下是一个典型的初始化函数:

void Timer_Init(void) {
    // 启用TIM2时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    // 配置时基结构体
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;  // 预分频值,72MHz / 7200 = 10kHz
    TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;    // 自动重装载值,10kHz / 10000 = 1Hz
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
    
    // 使能更新中断
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    // 配置NVIC
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    
    // 启动定时器
    TIM_Cmd(TIM2, ENABLE);
}

在这个例子中,预分频值设置为7199(因为从0开始),这样计数器时钟为72MHz / 7200 = 10kHz。自动重装载值设为9999,意味着计数器从0计数到9999后溢出,产生中断。因此,中断频率为10kHz / 10000 = 1Hz,即每秒一次。这种配置非常适合需要秒级定时的应用,比如实时时钟或数据记录。

中断服务函数中,我们需要检查中断标志位并清除它。以下是一个简单的中断处理函数:

void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        // 在这里处理中断任务,比如增加计数器
        counter++;
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

这段代码会在每次中断时增加一个全局变量counter。注意,中断服务函数要尽量简短,避免长时间占用CPU。如果需要复杂操作,可以考虑使用标志位在主循环中处理。

4. OLED显示驱动集成

OLED显示部分,我们需要集成一个驱动库。常见的是SSD1306的I2C驱动。首先,在工程中添加OLED的源文件和头文件。在main函数中,调用初始化函数OLED_Init()。通常,驱动库会提供显示字符串、数字和图形的函数。

初始化OLED后,我们可以在主循环中动态显示定时器的计数值。例如,在while(1)循环中,调用OLED_ShowNum()函数显示counter的值。为了减少屏幕闪烁,可以只更新数值部分,而不是整个屏幕。以下是一个示例代码片段:

int main(void) {
    // 系统初始化
    SystemInit();
    OLED_Init();
    Timer_Init();
    
    // 显示初始内容
    OLED_ShowString(1, 1, "Count:");
    
    while (1) {
        // 动态显示计数值
        OLED_ShowNum(1, 7, counter, 5);  // 在第1行第7列显示5位数字
        Delay_ms(10);  // 短暂延迟,避免CPU过载
    }
}

在这个例子中,OLED_ShowNum函数用于显示数字,参数分别表示行、列、数值和位数。我建议在显示前清除旧内容,以避免残影。例如,可以用OLED_Clear()清屏,但频繁清屏会导致闪烁,因此最好只更新变化的部分。

如果使用SPI接口的OLED,配置类似,但需在CubeMX中启用SPI外设,并连接对应的MOSI和SCK引脚。驱动代码会有所不同,但基本逻辑相同。实测中,I2C接口更简单,但SPI速度更快,适合高刷新率应用。

5. 动态显示与中断协同工作

现在,我们将定时器中断和OLED显示结合起来,实现动态更新。在中断服务函数中,我们增加计数器,并在主循环中显示这个值。这样,OLED就能实时反映定时器的中断次数。

为了优化性能,我通常使用一个全局变量作为标志位。在中断中设置标志位,在主循环中检查并处理显示。这能避免在中断中执行耗时操作。以下是修改后的代码:

volatile uint16_t counter = 0;
volatile bool update_display = false;

void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        counter++;
        update_display = true;
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

int main(void) {
    // 初始化代码
    SystemInit();
    OLED_Init();
    Timer_Init();
    
    OLED_ShowString(1, 1, "Count:");
    
    while (1) {
        if (update_display) {
            OLED_ShowNum(1, 7, counter, 5);
            update_display = false;
        }
        // 其他任务
    }
}

这种方法减少了中断处理时间,提高了系统响应性。如果显示更新较慢,可以考虑使用双缓冲或局部刷新技术。例如,只更新数字区域,而不是整个屏幕。

在实际项目中,我遇到过显示抖动的问题,原因是中断频率太高,导致主循环来不及处理。这时,可以调整定时器预分频值或重装载值,降低中断频率。例如,将预分频值增大,使中断频率降到10Hz以下,显示会更平滑。

6. 常见问题与调试技巧

在开发过程中,可能会遇到一些常见问题。比如,定时器不触发中断,可能是NVIC配置错误或中断标志未清除。我用逻辑分析仪或示波器检查定时器输出,确认中断是否产生。如果OLED无显示,检查I2C地址是否正确(通常是0x78或0x7A),以及接线是否牢固。

另一个常见问题是显示内容乱码。这可能是OLED驱动未正确初始化,或通信速率不匹配。我建议在初始化后添加延迟,确保OLED有足够时间启动。此外,确保驱动库与硬件兼容,例如SSD1306支持多种分辨率,需正确配置。

调试时,使用串口打印日志很有帮助。例如,在中断中打印计数值,确认定时器工作正常。如果资源紧张,可以用LED指示灯代替串口,通过闪烁频率判断程序状态。

电源噪声也可能影响定时器精度。在高速计数时,建议使用外部晶振,并提供稳定的电源。如果项目需要高精度定时,可以考虑使用高级定时器的编码器模式或外部时钟输入。

最后,优化代码结构,避免在中断中处理复杂逻辑。如果需要实时性高的任务,可以使用DMA传输数据,减少CPU开销。例如,用DMA将显示数据发送到OLED,提高效率。

7. 扩展应用与进阶思路

基本定时器中断和OLED显示的组合可以扩展到更多应用。比如,结合传感器数据采集,定时读取温度或湿度值,并实时显示在OLED上。我做过一个项目,用TIM2定时读取DHT11传感器,每秒更新一次显示,效果很好。

另一个进阶应用是实现菜单界面。通过按键中断切换显示内容,定时器控制刷新率。例如,用定时器生成软实时时钟,显示时间和日期。这需要更复杂的中断管理,但能提升用户体验。

对于低功耗项目,可以配置定时器在睡眠模式下工作,唤醒MCU处理任务后再次进入睡眠。这样能显著降低功耗,适合电池供电的设备。

如果想深入学习,可以探索通用定时器的输入捕获和PWM输出功能。例如,用定时器测量脉冲宽度,或生成PWM信号控制电机速度。OLED可以显示当前参数,方便调试。

总之,定时器和OLED是嵌入式开发中强大的工具组合。通过灵活配置,能实现各种实时显示功能。希望这篇分享能帮助大家快速上手,少走弯路。

python程序小工具——对比两个文件夹差异 如果需要对比确保文件是否修改,可以在获取当前文件夹下文件的函数get_files里面,添加记录文件的最后修改时间,与文件名进行拼接组合成key,这样在后续两文件夹对比时也可以分离出修改时间。功能说明:给了两个文件夹,需要对比出两个文件夹的文件不同之处,包括前一个文件夹比后一个文件夹减少了哪些文件或子文件夹,亦或是后一个比前一个多了多少。1、由于当前的程序只是对比了文件名相同与否,并不能保证后一个文件夹中的文件是否只是文件名相同,但是文件内容已经进行了修改。保留拓展名放置于key中。 阅读详情

相关推荐

Python实现文件夹或列表的比较与查找

希望这篇文章能够对初学者有所帮助。在我们的日常工作中,经常需要比较两个或多个文件夹或者列表中的数据差异,这时候,Python就能为我们提供便捷的解决方案。首先,我们需要比较两个文件夹中的内容异同,一种常见的方法是使用os模块执行文件夹遍历操作,然后使用set集合去重,得到各自的文件路径列表。这里使用os.listdir()获取文件夹内文件和文件夹的名字列表,set()函数将列表转换成集合,并使用集合操作实现了文件路径列表的差异计算。这里,我们首先将列表转换成集合,接着使用集合操作实现了列表数据的比较。

. 902

用python如何对比两个目录、文件差异,同名文件MD5是否一致

python对比两个目录下文件夹和文件名、同名文件md5是否一致

qingqinglianni的博客 2449

比较两个目录下的文件是否相同

Python在执行时,首先会将.py文件中的源代码编译成Python的byte code(字节码),然后再由Python Virtual Machine来执行这些编译好的byte code。这种机制的基本思想跟Java,.NET是一致的。

python对比两个文件夹内容并同步差异

【代码】python对比两个文件夹内容并同步差异。

qq_30258721的博客 585

chrome-headless-shell-mac-x64-160.0.8160.0(Canary).zip

内容概要:Chrome for Testing 官方 chrome-headless-shell 160.0.8160.0 x64 平台(金丝雀版通道),原版未修改,附来源说明。 适合人群:x64 上的自动化测试工程师、爬虫开发者、CI 环境搭建者。 使用场景及目标:①无头浏览器(Playwright/Puppeteer/Selenium 无界面自动化与爬虫的运行内核);②服务器/容器离线内置;③版本精准匹配(chromedriver 与 Chrome 需同大版本)。 其他说明:Chrome for Testing 为 Google 官方发布、允许自由分发的文件;本资源为第三方整理的下载便利服务。

多智能体-系统-形成-控制 附matlab代码.rar

多智能体-系统-形成-控制 附matlab代码.rar

Python实现文件与目录差异对比

一 点睛 当我们进行代码审计或校验备份结果时,往往需要检查原始与目标目录的文件一致性,Python的标准库已经自带了满足此需求的模块 filecmp。filecmp可以实现文件、目录、遍历子目录的差异对比功能。比如报告中输出目标目录比原始多出的文件或子目录,即使文件同名也会判断是否为同一个文件(内容级对比)等,Python 2.3或更高版本默认自带filecmp模块,无需额外安装。 filec...

实践求真知 5949

Python编程实现两个文件夹里文件的对比功能示例【包含内容的对比】

本文实例讲述了Python编程实现两个文件夹里文件的对比功能。分享给大家供大家参考,具体如下: #-*-coding:utf-8-*- #=============================================================================== # 目录对比工具(包含子目录 ),并列出 # 1、A比B多了哪些文件 # 2、B比A多了哪些文件 # 3、二者相同的文件:文件大小相同 VS 文件大小不同 (Size相同文件不打印:与Size不同文件显示未排序) #==========================================

python脚本处理---(不同文件夹中的文件对比、移动,提取指定类型文件、中文文件名转英文)

python脚本处理---(不同文件夹中的文件对比、移动,提取指定类型文件、中文文件名转英文)

qq_41920323的博客 714

具有PWM控制VSC-HVDC链路的IEEE30总线传输系统(Simulink仿真实现)

内容概要:本文构建了一个包含PWM控制VSC-HVDC链路的IEEE30节点电力传输系统,并基于Simulink平台完成了系统的建模仿真。该模型聚焦于高压直流输电(HVDC)技术在区域电网互联中的应用,采用电压源型换流器(VSC)与脉宽调制(PWM)技术实现高效、灵活的电能传输。研究重点在于分析VSC-HVDC链路在复杂多节点电网中对潮流分布、系统稳定性及电能质量的调控能力,特别关注其在区域电网互联、新能源大规模接入以及跨区域电力交换等场景下的动态响应特性与控制性能,为现代智能电网的发展提供技术支撑与仿真验证手段。; 适合人群:具备电力系统、电气工程或自动化等相关专业背景的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于研究VSC-HVDC在多节点电网(如IEEE30节点)中的建模与仿真方法;②分析PWM控制策略下HVDC链路对电网潮流分布、电压稳定性和故障穿越能力的影响;③为区域电网互联、新能源并网及智能电网调度等课题提供仿真基础和技术验证。; 阅读建议:此资源以Simulink仿真实现为核心,建议读者在掌握电力电子技术和电力系统分析基础知识的前提下,结合仿真模型深入理解VSC-HVDC的工作原理与控制策略。在学习过程中,应着重关注模型参数设置、控制环路设计及仿真结果的分析,以达到理论与实践相结合的目的。

基于KDE-CDF置信带的不确定综合能源系统鲁棒调度优化研究(Matlab代码实现)

内容概要:本研究针对不确定综合能源系统中的鲁棒调度优化问题,提出一种基于核密度估计-累积分布函数(KDE-CDF)置信带的建模方法,用以精确刻画风能、光伏及负荷等不确定性因素的非正态概率分布特征。通过构建KDE-CDF模型,能够有效捕捉实际运行中新能源出力与负荷需求的波动性与随机性,并在此基础上设计鲁棒优化调度框架,提升系统在不确定性环境下的运行可靠性与经济性。该方法结合Matlab编程实现,综合考虑系统运行成本、峰谷差、碳排放等多重目标,实现多维度协调优化。研究还探讨了与智能优化算法(如粒子群算法)相结合的应用路径,增强了模型的求解效率与工程实用性,为含多种储能装置、电转气设备及碳捕集系统的复杂综合能源系统提供了科学的调度决策支持。; 适合人群:具备电力系统分析、优化理论基础及Matlab编程能力的研究生、科研人员,以及从事综合能源系统规划、运行与调度工作的工程技术人员。; 使用场景及目标:①解决高比例可再生能源接入背景下综合能源系统调度中的不确定性建模难题;②提升调度方案在面对新能源强波动性时的鲁棒性与适应能力;③为融合多类型灵活性资源(如储能、电转气、碳捕集)的综合能源系统提供精细化、可落地的优化运行策略。; 阅读建议:建议读者在掌握概率统计、随机优化与电力系统运行基础知识的前提下,结合文中提供的Matlab代码进行实践操作,重点关注KDE-CDF置信带的构建流程及其在鲁棒优化模型中的嵌入机制,通过调整输入数据分布、参数设置与场景配置开展仿真对比实验,深入理解不确定性建模精度对调度决策质量的影响,进而掌握从数据驱动角度提升系统鲁棒性的关键技术路径。

【工具脚本】python比较两个目录的文件差异、对比

python代码如下,替换下aPath 和bPath为你要比较的文件夹路径即可 # -*-coding:utf-8-*- #=============================================================================== # 目录对比工具(包含子目录 ),并列出 # 1、A比B多了哪些文件 # 2、B比A多了哪些文...

linxinfa的专栏 1万+

含分布式电源的配电网可靠性评估研究(Matlab代码实现)

内容概要:本文系统研究了含分布式电源的配电网可靠性评估方法,基于Matlab代码实现了完整的评估模型与算法框架。研究深入分析了分布式电源接入后对配电网结构与运行特性的影响,重点探讨了其对供电可靠性的作用机制。采用序贯蒙特卡洛模拟法对系统各类状态进行抽样与仿真,综合考虑了分布式电源出力的随机性、负荷波动性以及网络拓扑变化等多种不确定性因素,精确计算了系统及负荷点的多项可靠性指标。通过在标准测试系统上的仿真实验,验证了所提方法的有效性和实用性,为新型电力系统环境下配电网的规划、运行与可靠性提升提供了有力的技术支撑和决策依据。; 适合人群:具备电力系统分析、概率统计及可靠性基础理论知识,熟悉Matlab编程语言,从事电力系统规划、运行、可靠性评估等相关工作的科研人员、高校研究生以及电力行业工程师。; 使用场景及目标:①掌握含分布式电源的现代配电网可靠性评估的核心理论与关键技术;②学习并实践基于序贯蒙特卡洛模拟的电力系统可靠性分析算法的Matlab实现方法;③为实际工程中分布式电源的优化配置、配电网的升级改造以及制定可靠性提升策略提供科学的仿真工具和量化分析依据。; 阅读建议:建议读者结合文中提供的Matlab代码,逐行阅读并运行程序,重点理解系统建模、状态抽样、潮流计算与指标统计等核心模块的实现逻辑。可尝试调整分布式电源的类型、容量、接入位置及负荷水平等参数,观察其对系统可靠性指标的影响趋势,从而深化对系统动态行为与关键影响因素的理解。

利用python对比一下目录里面文件

有时候会进行文件转移一般都是rsync,但是rsync转移会花费好几个小时,转移期间还是会有新文件上传,而且转移结束后需要改读写的路径到新路径,这样会丢失转移期间的文件,所以写了一个简单的python检查一下, 代码如下 记得给我宝贵意见: #!/usr/bin/python # -*- coding: UTF-8 -*- ''' auth yufei 2015-5-10 转文件了,转移...

一方 524

OctoMag: An Electromagnetic System for 5-DOF Wireless Micromanipulation

电磁线圈组驱动经典系统,可以作为参考。 OctoMag: 用于5自由度无线微操作的一个电磁铁系统 OctoMag: An Electromagnetic System for 5-DOF Wireless Micromanipulation [1] Paper Link Authors: J. J. Abbott, etc. 2010, TRO IEEE Transactions on Robot...

XU Yangxin的博客 1666

【QT】基于QSerialPort的跨平台串口通信实战指南

本文是一份基于Qt QSerialPort模块的跨平台串口通信实战指南。详细介绍了从硬件基础、QSerialPort核心类使用、参数配置、设备自动发现到数据异步读写和错误处理的完整流程,并通过构建一个功能齐全的串口调试助手实例,帮助开发者快速掌握在Windows、Linux和macOS系统下进行高效、稳定的串口应用开发。

a1b2c3d的博客 983

python实现文件夹文件遍历及比对

在读文件的时候往往需要遍历文件夹,python的os.path包含了很多文件、文件夹操作的方法。下面列出: os.path.abspath(path) #返回绝对路径 os.path.basename(path) #返回文件名 os.path.commonprefix(list) #返回多个路径中,所有path共有的最长的路径。 os.path.dirname(path) #返回文件路径

xiaxuesong666的博客 4739

JetLinks社区版VS企业版:手把手教你用PostgreSQL+Redis搭建物联网中台(Win7实测)

本文详细对比了JetLinks社区版与企业版的核心差异,并提供了在Windows 7系统上,使用PostgreSQL和Redis搭建物联网中台的完整部署教程。文章深入解析了从环境准备、后端服务构建到前端部署的每一步,为开发者在资源有限环境下构建高性价比物联网平台提供了清晰的实战指南。

w1x2y3的博客 308

【Python】比较两个目录下的所有文件版本、并找出版本异常的文件

使用方法 comparison.py current_dir standard_dir 代码如下,欢迎参考 ???? from filecmp import dircmp import os from win32com.client import Dispatch import time import argparse # 已知某个文件名在某个目录(或者该目录子目录)中,获取文件全路径 def getFileFullPath(folder, filename): filepath_list =

KEEP MOVING. 554

基于opencv-ANN的水果识别模型训练

本文通过opencv-ann-mlp训练模型,实现对五种水果进行分类识别。本文详细介绍该项目的各个过程,包括数据准备、预处理、样本读取、训练数据集制作、训练标签制作、模型参数设置、模型训练,模型测试验证等,总结该过程需要注意的事项。

qq_15985873的博客 3975

【VoxCPM2】在Windows上从零搭建VoxCPM2 语音生成和语音克隆AI算法

建议你了解清楚VoxCPM2,再来考虑是否需要自己在本地搭建。

AnChenliang_1002的博客 760
上一篇: 1553B协议芯片的时空对话:寻址空间与读写时序的架构哲学
下一篇: RK3588多路视频拼接与显示:RGA与GPU的协同加速实践
ruby5
博客等级 码龄15年 29粉丝 893原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值