开发环境:keil MDK V5.10
操作系统:windows 7(32位)
目标硬件:STM32F103C8
问题描述:使用STM32的systick定时器实现RTC功能。具体方法为systick滴答计时器配置为1ms时间间隔的滴答中断,定义一个RTC结构体,包含年、月、日、时、分、秒。在每进一次systick中断服务程序中更新一次RTC的值。主程序通过不停地获取RTC的时钟,每一秒钟使用printf函数输出当前的时间。测试过程发现绝大多数时间系统正常工作,但依然存在部分情况系统无法进行正常的输出。相关代码和测试结果如下:
/**
* @brief 系统滴答定时器中断服务程序,主要功能为更新实时时钟
*
* @note 无
* @param 无
* @retval 无
*/
void systick_isr(void)
{
systick.tick_num++;
rtc.ms++;
rtc_update(&rtc);
}
/**
* @brief 获取系统实时时钟
*
* @note 无
* @param 用于存放当前系统实时时钟数据的结构体的指针
* @retval 无
*/
void get_rtc(time_t *ptime)
{
*ptime = rtc;
}
时钟测试程序片段
while(1)
{
get_rtc(&tprtc);
if(j != tprtc.sec)
{
printf("time:%02d-%02d-%02d %02d:%02d:%02d\r\n",tprtc.year,tprtc.mon,tprtc.date,tprtc.hour,tprtc.min,tprtc.sec);
j = tprtc.sec;
LEDTX_TOGGLE();
LEDRX_TOGGLE();
LEDNET_TOGGLE();
}
}
测试结果如下:
time:14-04-28 01:55:55
time:14-04-28 01:55:56
time:14-04-28 01:55:57
time:14-04-28 01:55:58
time:14-04-28 01:55:59
time:14-04-28 01:55:00
time:14-04-28 01:56:01
time:14-04-28 01:56:02
time:14-04-28 01:56:03
原因分析:get_rtc函数在使用中断服务程序改变变量rtc时,没有进行保护导致赋值错误。具体原因为,rtc是一个结构体,在get_rtc函数中尽管只使用了一行代码进行赋值操作,实际上应该是很多条指令周期。假设其拷贝数据过程按年、月、日、时、分、秒的顺序进行拷贝,而当get_rtc函数拷贝完“分”的时候,也就是上边测试结果中的“55”这个数值拷贝完之后,发生了中断,中断中秒由原来的59变为0,分变为56,中断服务程序退出时,get_rtc继续拷贝秒,此时秒为0,从而出现以上错误结果。针对该问题可以在进行拷贝前禁止systick中断来处理,代码如下:
void get_rtc(time_t *ptime)
{
systick_irq_dis();//禁止systick中断
*ptime = rtc;
systick_irq_en();//使能systick中断
}
修改后测试发现比原来更加糟糕,程序几乎无法打印出任何信息来。经过反复分析和仿真发现禁止systick中断函数及使能systick中断函数均为操作寄存器相应的位来使能和禁止中断的。而该寄存器一旦被读或者被写将导致已经产生的中断标志位失效。换言之就是说当在执行"*ptime = rtc"这句代码的时候发生了中断,中断标志置位,理论上当使能中断后就应该进行中断处理,悲哀的是使能中断后中断标志被清空,无法产生中断,从而不能进入中断服务函数,最终导致rtc非常困难才能被更新,程序长期无法正常打印。
经验总结:
1.主程序代码操作中断服务函数需要改变得变量时需要谨慎,一般是在操作前关闭中断,使用之后立即恢复中断。
2.在使用关闭中断和恢复中断函数时务对该操作是否会影响中断标志位进行考虑!
3.如果不关闭中断,那么必须保证中断函数对变量的操作应该在一个指令周期完成,也就是中断操作为原子操作;同时外部程序使用该变量的操作也应该在一个指令周期完成,为原子操作。
关键字:STM32 systick 定时器中断 RTC
引用地址:
使用STM32的systick定时器中断实现RTC工作过程出错
推荐阅读最新更新时间:2024-03-16 16:09
STM32调试DEBUG时需要了解那些知识相关资料概述
学习STM32开发,肯定少不了DEBUG调试这一步骤。那么,本文带你了解一下这个调试相关的知识。 本文以STM32F1、Cortex-M3为例,其它系列芯片或内核,原理相同或类似。 1概况 在STM32中,有很多调试组件。使用它们可以执行各种调试功能,包括断点、数据观察点、 闪存地址重载以及各种跟踪。 STM32F1使用Cortex-M3内核,该内核内含硬件调试模块,支持复杂的调试操作。 硬件调试模块允许内核在取指(指令断点)或访问数据(数据断点)时停止。内核停止时,内核的内部状态和系统的外部状态都是可以查询的。完成查询后,内核和外设可以被复原,程序将继续执行。 当STM32F10x微控制器连接到调试器并开始调试时,调试器
[单片机]
stm32 GPIO口配置操作
stm32里面最基本的思路就是使用外设相应寄存器之前,必须开启控制对应寄存器的时钟,读者可到技术手册中查询相应的时钟控制的相应的寄存器。 这里首先开启stm32普通io口的时钟。 GPIO 作为通用输入输出口使用时,当有外部中断设置时才需要开启AFIO时钟,否则不需要开启AFIO 时钟。 然后就是进行gpio结构体的初始化设置 GPIO 常用设置里包括三个结构体的使用如下: 1、GPIO_InitTypeDef为GPIO的基本参数设置结构体,其中GPIO_Pin表示引脚号,GPIO_Speed表示引脚的速度,GPIO_Mode表示引脚的输入输出模式选择。通过这三个基本设置实现了
[单片机]
STM32:stm32f10x_gpio.c中GPIO_Init的分析说明
1 /** 2 *函数功能:初始化引脚模式 3 *参数说明:GPIOx,该参数为GPIO_TypeDef 类型的指针,指向GPIO 端口的地址 4 * GPIO_InitTypeDef:GPIO_InitTypeDef 结构体指针,指向初始化变量 5 */ 6 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) 7 { 8 uint32_t currentmode =0x00,currentpin = 0x00,pinpos = 0x00,pos = 0x00; 9 uint32_t tmpreg = 0x00, pinmas
[单片机]
STM32之串口通信
实验目的: 实现利用串口1 不停的打印一个信息到电脑上,同时接收从串口发过来的数据,把发送过来的数据直接送回给电脑。 实验平台: 基于STM32F103C8T6的彩屏开发板 硬件接口: 注意:因为我的开发板上的串口和LED共用了PA9和PA10,所以在使用USART1时务必屏蔽LED,不然两者会互相影响而导致实现现象无法呈现。 相关寄存器: 1,串口时钟使能。串口作为STM32 的一个外设,其时钟由外设时钟使能寄存器控制,这 里我们使用的串口1 是在APB2ENR 寄存器的第14 位。 2,串口复位。串口1 的复位是通过配置APB2RSTR 寄存器的第14 位来实现的。。通
[单片机]
初涉STM32之浅谈时钟使能问题
作为一个STM32的菜鸟级人物,我刚开始接触STM32时,其实和当年开始学习51单片机的心理是一样的。茫然,谁说不是呢?但是,正常的学习途径无非就是看书,然后敲代码,最后烧程序,有问题就check,然后再继续烧,我都怀疑我快成了火头工。因为在我的印象中,只有这类职业才和“烧”有着密不可分的联系。即使当一名敬业又牛逼的火头工是我毕生的梦想。OK,不侃了。我希望,通过写日志把我作为一个菜鸟在学习STM32中的问题记录下来,同时以我为鉴,规避那些没有必要的破事。 1. 学习STM32要不要基础 原则上它应该是需要的,但是,我们也能发现很多人也是没有基础的。比如说,我们实验室的大师兄原来是管理专业,但是现在相当牛逼,软硬皆通。如果你和很多
[单片机]
STM32 端口复用&重映射
下面跟大家说一下STM32单片机的端口重映射,因为是以自己为实例.这里是以USART1的重映射为例.. 因为我要一个TFT_LCD屏的主控板,考虑到FSMC 我选用了STM32F103VCT6 型号的CPU,一不小心串口接到USART1上了.因为在调程序时才发现错了,没得办法,只能通过端口重映射来解决.但是以前没用过端口重映射,只闻其名,未用其身,所以..呵呵 ...只能从头去看了. STM32上有很多I/O口,也有很多的内置外设想I2C,ADC,ISP,USART等,为了节省引出管脚,这些内置外设基本上是与I/O口共用管脚的,也就是I/O管脚的复用功能。但是STM32还有一特别之处就是:很多复用内置的外设的I/O引脚可以通过
[单片机]
用STM32内置的高速ADC实现简易示波器
做一个数字采样示波器一直是我长久以来的愿望,不过毕竟这个目标难度比较大,涉及的方面实在太多,模拟前端电路、高速ADC、单片机、CPLD/FPGA、通讯、上位机程序、数据处理等等,不是一下子就能成的,慢慢一步步来呗,呵呵,好歹有个目标,一直在学习各方面的知识,也有动力:)由于高速ADC涉及到采样后的数据存储问题,大量的数据涌入使得单片机无法承受,因此通常需要用外部高速RAM加CPLD配合,或者干脆用大容量的 FPGA做数据存储处理等,然后通知单片机将数据发送出去。这部分实在是难度比较大,电路非常复杂,自己是有心无力啊,还得慢慢地技术积累。。。 正好ST新推出市场的以CORTEX-M3为核心的STM32,内部集成了2个1Msps 12
[单片机]