实验四 STM 应用设计
1 实验目的
1). 综合掌握 STM32 的 LED 显示、通用定时器 TIM2、中断控制及串口通讯的原理, 完成数据串口数据写到 PC 机上;
2). 设计一个具体的应用;
3). 掌握基于 STM32 工程开发流程。
2 实验环境
1). 硬件:1 个空气温湿度传感器模块、1 个 ST-Link 调试器、1 根 USB2.0 方口线、1
根 USB3.0 数据线、1 台 PC 机;
2). 软件:Windows 7/XP、MDK 集成开发环境。
3 实验功能
通过使用STM32的ADC模块将模拟信号转换为数字信号,通用定时器 TIM2 中断方式控制LED灯当温度超过设定阈值时亮起报警,将事实温度通过串口打印出来。
4 实验步骤
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.)点击按钮 ,将程序下载到温湿度传感器模块中。下载成功后,信息框显示下图
中所示的信息,表明程序下载成功并已自动运行。
5 实验程序
#include"stm32f10x.h"
#include<stdio.h>
void gpio_init(void) //gpio初始化
{
GPIO_InitTypeDef GPIO_InitStructure; //初始化配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOF, ENABLE); //定义结构体
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;//PB7 的推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // PA 9 做TX脚进行输出。TX:发送数据输出端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // PA 10 做RX引脚做输入。RX:接收数据输入端口
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void led_init(void) // 点亮 User1 指示灯
{
GPIO_SetBits(GPIOB,GPIO_Pin_4);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_ResetBits(GPIOB, GPIO_Pin_7);
}
void USART1_Config(void){ //USART的初始化配置
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//开启USART1的时钟
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 设置数据位:1个起始位, 8个数据位
USART_InitStructure.USART_StopBits = USART_Parity_No;// 1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // CTS失能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //使能发送和接收
USART_Init(USART1, &USART_InitStructure); //调用库函数,初始化USART1
USART_Cmd(USART1, ENABLE);
}
int fputc(int ch, FILE *f)//写字符文件函数
{
USART_SendData(USART1, (unsigned char)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}
return (int)ch;
}
// 时钟函数设置
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定义一个定时器初始化参数结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启APB2的TIM2的外设时钟
TIM_DeInit(TIM2); //TIM2相关参数进行缺省设置
TIM_TimeBaseStructure.TIM_Period = 10000; //自动装载值为1000
TIM_TimeBaseStructure.TIM_Prescaler = (7200 - 1); //预分频系数为7199
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//单倍分频
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//通过结构体初始化相关寄存器
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除溢出中断标志
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能TIM2中断, 允许更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
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
}
//ADC初始化
void T_Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );
// 开启外设时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置分频因子为 6 则时钟频率为 72M/6=12MHz
ADC_DeInit(ADC1); // 复位 ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立工作模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;// 模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 转换由软件触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // ADC 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 顺序进行规则转换的 ADC 通道数为 1
ADC_Init(ADC1, &ADC_InitStructure); // 初始化外设 ADC1 的寄存器
ADC_TempSensorVrefintCmd(ENABLE); // 开启内部温度传感器
ADC_Cmd(ADC1, ENABLE); // 使能 ADC1
ADC_ResetCalibration(ADC1); // 执行复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); // 等待复位校准结束
ADC_StartCalibration(ADC1); // 执行 ADC1 校准
while(ADC_GetCalibrationStatus(ADC1)); //等待 ADC1 校准结束
}
int main(void)
{
gpio_init();
led_init();
USART1_Config();
TIM2_Configuration();
TIM2_NVIC_Configuration();
T_Adc_Init();
printf("welcome to the temperature warning system!");
while(1);
}
float adcx,temperate,temp;
uint16_t T_Get_Adc(uint8_t ch)
{
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 使能 ADC1 的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )); // 等待转换结束
return ADC_GetConversionValue(ADC1); // 返回最近一次 ADC1 规则组的转换结果
}
void TIM2_IRQHandler(void)
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
// 0.1S 时间到,检测到 TIM2 中断
{
adcx=T_Get_Adc(ADC_Channel_16); // 读取 ADC1 转换值
temp=(float)adcx*(3.3/4096); // 计算电压值
temperate=(1.43-temp)/0.0043+25; // 计算温度
if(temperate >= 30)
{
printf("warning:temperate is so high!\n");
printf("temp:%0.1f℃ \r\n", temperate); // 打印警报消息
GPIO_ResetBits(GPIOB,GPIO_Pin_5);//指示灯亮
}
else{
printf("the temperate is proper!\n");
printf("temp:%0.1f ℃\r\n", temperate); // 通过 USART1 打印温度值
}
}
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); // 清除中断标志位
}
6 实验结果
程序成功运行后,将可以看到User1灯常亮,代表工作状态, 当温度高于30摄氏度时橙灯亮开始报警。
7 实验心得
通过综合实验熟悉STM32嵌入式系统的设计与使用,尤其是ADC将模拟信号转换为数字信号。实现的功能为每过一秒发送一次温度数据,如果高于30摄氏度就报警,并亮起橙灯,熟悉了中断的ADC的用法。