1).掌握使用 STM32 的通用定时器 TIM2 实现 1s 定时的方法;
2).掌握 STM32 的定时器的中断配置方法;
3).掌握中断方式控制流水灯的原理
1). 硬件:1 个空气温湿度传感器模块、1 个 ST-Link 调试器、1 根 USB2.0 方口线、1
根 USB3.0 数据线、1 台 PC 机;
2). 软件:Windows 7/XP、MDK 集成开发环境。
通过使用 STM32 的通用定时器 TIM2 中断方式控制流水灯,程序成功运行后,将可以看到 Status、RS485-R、RS485-T、User1 四个指示灯每隔约一秒的时间轮流闪烁。
1.)将 USB3.0 数据线的一端连接感知执行模块的 USB3.0 调试烧写口,另一端连接
ST-Link 调试器的“Debug”接口。
2.)将 USB2.0 方口线的一端连接 PC 机的 USB 口,另一端连接 ST-Link 调试器的
“USB-232”接口,连接正确后效果如图 4.5 所示。
3.)双击打开工程文件“STM32-Timer.uvproj”。
4.)在工具栏中点击按钮 ,编译工程成功后,信息框会出现下图所示的信息。如果
编译失败,请确认相关选项是否配置正确。
5.)确认与硬件调试有关的选项已设置正确。
6.)点击按钮 ,将程序下载到温湿度传感器模块中。下载成功后,信息框显示下图
中所示的信息,表明程序下载成功并已自动运行。
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include
void GPIO_init(void) // GPIO 的初始化配置
{
GPIO_InitTypeDef GPIO_InitStructure; // 定义一个 GPIO_InitTypeDef 类型的结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO , ENABLE);
// 开启 AFIO 时钟和 GPIOB 的外设时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 禁用 JTAG 功能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6|GPIO_Pin_7;
// 选择要控制的 GPIOB 引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚速率为 50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚模式为通用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure); // 调用库函数,初始化 GPIOB
}
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 定义一个定时器初始化参数结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); // 开启 APB1 的 TIM2 外设时钟
TIM_DeInit(TIM2); // 复位TIM2定时器,使之进入初始状态
TIM_TimeBaseStructure.TIM_Prescaler= (7200 - 1); // 设置预分频系数为(7200-1)
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseStructure.TIM_Period=(10000-1); // 自动加载值设置,累计 10000 个时钟周期(1s)后溢出
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 根据 TIM_TimeBaseStructure 中指定的参数初始化 TIM2 里的相关寄存器
TIM_ClearFlag(TIM2, TIM_FLAG_Update); // 清除溢出中断标志
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); // 使能 TIM2 中断,允许更新中断
TIM_Cmd(TIM2, ENABLE); // 使能 TIM2 外设
}
void TIM2_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; // 定义 NVIC 初始化结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 选择中断优先级分组 0
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 选择配置 TIM2 全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 占先优先级为 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1; // 响应优先级为 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能 TIM2 中断通道
NVIC_Init(&NVIC_InitStructure); // 根据以上配置初始化 NVIC
}
int main()
{
GPIO_init();
GPIO_SetBits(GPIOB,GPIO_Pin_4);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
TIM2_NVIC_Configuration();
TIM2_Configuration();
while(1)
{ }
}
/*
int led_state=0;
void TIM2_IRQHandler(void)
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) // 1S 时间到,检测到 TIM2 中断
{
led_state++; // 状态加 1
switch (led_state)
{
case 1: // 状态 1:灭掉 User1,点亮 Status
GPIO_SetBits(GPIOB,GPIO_Pin_7);
GPIO_ResetBits(GPIOB,GPIO_Pin_4);
break;
case 2: // 状态 2:灭掉 Status,点亮 RS485-R
GPIO_SetBits(GPIOB,GPIO_Pin_4);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
break;
case 3: // 状态 3:灭掉 RS485-R,点亮 RS485-T
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
break;
case 4: // 状态 4:灭掉 RS485-T,点亮 User1
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
led_state=0; // led_state 置 0,下个 1s 时间到后可再次进入状态 1
break;
}
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); // 清除中断标志位
}
}*/
程序成功运行后,将可以看到 Status、RS485-R、RS485-T、User1 四个指示灯每隔约
一秒的时间轮流闪烁,效果见下图。
通过实验熟悉和掌握了如何使用 STM32 的通用定时器 TIM2 实现定时一定时间的功能,所要定时的时间=(计数器数值+1)*(预分频器数值+1)/脉冲频率。
知道了如何将中断服务程序写入文件"stm32f10x_it.c"中,而后在文件中"main.c"调用此程序
1)掌握使用 STM32 的通用定时器 TIM2 实现 1s 定时的方法;
2)掌握如何使用 STM32 的串口发送和接收数据。
1)硬件:1 个温湿度传感器模块、1 个 ST-Link 调试器、2 根 USB2.0 方口线、1 根 USB3.0 数据线、 1 台 PC 机;
2)软件:Windows 7/XP、MDK 集成开发环境
通过调试口实现秒表功能,每秒显示一次
1)、将 USB3.0 数据线的一端连接感知执行模块的 USB3.0 调试烧写口,另一端连接
ST-Link 调试器的“Debug”接口。
2)、 将第 1 根 USB2.0 方口线的一端连接 PC 机的 USB 口,另一端连接 ST-Link 调试器的“USB-Debug”接口。
3)、将第 2 根 USB2.0 方口线的一端连接 PC 机的 USB 口,另一端连接 ST-Link 调试器的“USB-232”接口。
4)、双击打开【配套光盘\03-常用工具\01-硬件开发包\09-串口调试工具】目录下的串口
调试器,选择正确的端口号(可参照 1.2.2 查看串口端号),波特率设为 9600,其他均保
持默认设置,点击按钮“打开串口”即可,效果见下图。
5)、双击打开工程文件“STM32-USART.uvproj”。
6)、在工具栏中点击按钮,编译工程,编译成功后,信息框会出现下图所示的信息。如
果编译失败,请参照 1.2.1.2 中的内容,确认相关选项是否配置正确。
#include
#include
void gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA和GPIOB的外设时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//PB7 User1指示灯
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置引脚速率
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//选择引脚模式为通用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure); //调用库函数初始化,初始化GPIOB
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//PA9 串口发送
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //调用库函数初始化,初始化GPIOA
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10;//PA10 串口接收
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void TIM2_Configuration(void) //定时器每 1s 产生一次中断
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 定义一个定时器初始化参数结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); // 开启 APB1 的 TIM2 外设时钟
TIM_DeInit(TIM2); // 将外设 TIM2 的寄存器重设为缺省值
TIM_TimeBaseStructure.TIM_Prescaler= (7200 - 1); // 设置预分频系数为(7200-1),计数器输入时钟频率为 10KHz
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 向上计数模式,,每 100μs 计一次数。
TIM_TimeBaseStructure.TIM_Period=(10000-1); // 自动加载值设置,累计 10000 个时钟周期(1s)后溢出
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 根据 TIM_TimeBaseStructure 中指定的参数初始化 TIM2 里的相关寄存器
TIM_ClearFlag(TIM2, TIM_FLAG_Update); // 清除溢出中断标志
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); // 使能 TIM2 中断,允许更新中断
TIM_Cmd(TIM2, ENABLE); // 使能 TIM2 外设
}
void TIM2_NVIC_Configuration(void) //中断配置
{
NVIC_InitTypeDef NVIC_InitStructure; // 定义 NVIC 初始化结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 选择中断优先级分组 0
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 选择配置 TIM2 全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级为 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1; // 响应优先级为 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能 TIM2 中断通道
NVIC_Init(&NVIC_InitStructure); // 根据以上配置初始化 NVIC
}
void USART1_Config(void)
{
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitStructure.USART_BaudRate =115200;//波特率115200
USART_InitStructure.USART_WordLength= USART_WordLength_8b;//1起始位,8数据位。共9位。
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//没有奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//失能CTS硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //使能Tx,Rx
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1,ENABLE);
}
int fputc(int ch,FILE* fp)//重定向函数 (把一个字符写到文件中)
{
USART_SendData(USART1,(unsigned char) ch); //unsigned char没有符号位,因此能表示的数据范围是0~255
while (USART_GetFlagStatus(USART1 ,USART_FLAG_TXE) == RESET); //发送寄存器非空,循环等待 (USART_GetFlagStatus检测发送寄存器TXE是否非空)
return (int)ch;
}
int main()
{
gpio_init();
GPIO_ResetBits(GPIOB,GPIO_Pin_7);//点亮User1指示灯
TIM2_Configuration(); //定时器每 1s 产生一次中断
TIM2_NVIC_Configuration(); //中断配置
USART1_Config();
while(1){
};
}
int sec=0,min=0,hour=0;
void TIM2_IRQHandler(void)//中断服务函数
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) // 1S 时间到,检测到TIM2 中断
{
sec++;
if(sec==60){
sec=0; //秒计数
min++;
if(min==60){
min=0; //分计数
hour++;
}
}
if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET) // 等待 USART1 接收数据完毕 ((RXNE读数据寄存器非空)USART_GetFlagStatus检测该位是否为1)
{
printf("%d:%d:%d \n",hour,min,sec);//输出时分秒
}
}
TIM_ClearFlag(TIM2 , TIM_FLAG_Update); //清楚中断标志位
}
通过TIM2配置实现闹钟,注意初始化,否则会影响结果的输出。注意局部变量的控制和NVIC的初始化。