(本篇博客有很多还没讲解很细致,先贴出代码,等有时间再进行注解)
设计一个电压测量监控设备,定时通过串口向 PC 机发送电压值,通过串口接收系统配置参数并保存到 E2PROM 中。设备硬件部分主要由电源部分、控制器单元、串口部分、存储单元组成,系统框图如图 1 所示 :
设计任务及要求
1. RTC 实时时钟
使用 STM32 内部 RTC 完成相关功能,设备上电后,时间初始化为 23 时 59 分 55 秒,默认定时上报电压时间为 0 时 0 点 0 分。
2. ADC 测量功能
设备采集电位器 R37 输出的电压信号 V1,并通过 LCD 显示。当 V1>VDD*k 时,指示灯LD1 以 0.2 秒为间隔闪烁,闪烁功能可以通过按键关闭;VDD为 3.3V;k 默认值为 0.1,保存在 E2PROM 中并可以通过串口修改配置。
3. 串行功能
3.1 设定 k 值,可设置范围 0.1 ~ 0.9
格式:【命令类型】【数值】【命令结束标志】
举例:
“k0.1\n”
设置 k 值为 0.1;
设备接收到命令执行后,回复“ok\n”。
3.2 定时上报电压 V1
格式:【V1 电压值】+【k 值】+【时间】【命令结束标志】
举例:
“2.21+0.1+123030\n”
12 时 30 分 30 秒上报电压值为 2.21V,k 值为 0.1
说明:串口设定 9600 波特,数据位 8,停止位 1,无校验位;没有发送或发送错误
的控制命令时,设备不做回应。
4. LCD 显示
设备上电默认通过 LCD 显示电位器输出电压 V1(保留小数点后两位有效数字)、k 值、指示灯闪烁报警功能状态和系统时间,显示界面如图 1 所示:
5. 按键功能
“B1”按键设定为“功能”按键,打开/关闭指示灯闪烁报警功能,默认为打开状态;
“B2”按键设定为“设置”按键,设置设备自动上报电压时间,按下 B2 后,LCD 显示界面如图 2 所示,此时通过按键 B3 切换选择时、分、秒,通过按键 B4 进行调整,完成调整后,按下 B2 按键,更新自动上报时间,并返回图 1 所示的 LCD 显示界面。
#include "stm32f10x.h"
#include "lcd.h"
#include "IO.h"
#include "stdio.h"
#include "i2c.h"
u32 TimingDelay = 0;
u8 string[20];
u8 RXCUNT = 0;
u8 RXOVER = 0;
u8 RXBUF[20] = {0};
u8 RTC_flag = 0;
u32 TimeVal;
u8 key_read_flag = 0;
u8 _200ms_flag = 0;
float ADC_val;
float k;
u8 i;
extern u16 LED_MODE;
extern u8 B1_ALA_Flag;
extern u8 B2_Set_Flag;
extern u8 ALA_hour,ALA_min,ALA_sec;
void Delay_Ms(u32 nTime);
u8 hour,min,sec;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
SysTick_Config(SystemCoreClock/1000);
i2c_init();
USART2_Init(9600);
RTC_Init(23,59,55);
ADC1_Init();
LED_Init();
KEY_Init();
k = _24c02_Read(0xaa) / 10.0;
if(RXOVER == 1)
{
RXOVER = 0;
if(((RXBUF[3] - 0x30) >= 1) && ((RXBUF[3] - 0x30) <= 9))
{
k = (RXBUF[3] - 0x30) / 10.0;
_24c02_Write(0xaa,RXBUF[3] - 0x30);
USART2_SendString((u8*)"OK\n");
}
for(i=0;i<20;i++)
{
RXBUF[i] = 0;
}
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
}
if(RTC_flag == 1) //RTC
{
RTC_flag = 0;
TimeVal = RTC_GetCounter();
hour = TimeVal / 3600;
min = TimeVal % 3600 / 60;
sec = TimeVal % 3600 % 60;
if(TimeVal == (ALA_hour * 3600 + ALA_min * 60 + ALA_sec))
{
for(i=0;i<20;i++)
{
string[i] = 0;
}
sprintf((char*)string,"%.2f+%.1f+%.2d%.2d%.2d\n",ADC_val,k,ALA_hour,ALA_min,ALA_sec);
USART2_SendString(string);
}
}
if(key_read_flag == 1) // KEY
{
KEY_Read();
key_read_flag = 0;
}
void KEY_Read(void)
{
static u16 key1_sum = 0,key2_sum = 0,key3_sum = 0,key4_sum = 0;
if(KEY1 == 0)
{
key1_sum++;
if(key1_sum == 1)
{
B1_ALA_Flag ^= 1;
}
}else
{
key1_sum = 0;
}
if(KEY2 == 0)
{
key2_sum++;
if(key2_sum == 1)
{
B2_Set_Flag ^= 1;
LCD_ClearLine(Line0);
LCD_ClearLine(Line1);
LCD_ClearLine(Line2);
LCD_ClearLine(Line3);
LCD_ClearLine(Line4);
LCD_ClearLine(Line5);
LCD_ClearLine(Line6);
LCD_ClearLine(Line7);
LCD_ClearLine(Line8);
LCD_ClearLine(Line9);
}
}else
{
key2_sum = 0;
}
if(KEY3 == 0)
{
key3_sum++;
if((key3_sum == 1) && B2_Set_Flag)
{
B3_Select_Flag++;
if(B3_Select_Flag > 2)
{
B3_Select_Flag = 0;
}
}
}else
{
key3_sum = 0;
}
if(KEY4 == 0)
{
key4_sum++;
if((key4_sum == 1) && B2_Set_Flag)
{
if(B3_Select_Flag == 0)
{
ALA_hour++;
if(ALA_hour >= 24) ALA_hour = 0;
}else
if(B3_Select_Flag == 1)
{
ALA_min++;
if(ALA_min >= 60) ALA_min = 0;
}else
if(B3_Select_Flag == 2)
{
ALA_sec++;
if(ALA_sec >= 60) ALA_sec = 0;
}
}
}else
{
key4_sum = 0;
}
}
if(!B2_Set_Flag)
{
sprintf((char*)string," V1 : %.2f ",ADC_val);
LCD_DisplayStringLine(Line3, string);
sprintf((char*)string," k : %.1f ",k);
LCD_DisplayStringLine(Line4, string);
if(B1_ALA_Flag)
{
LCD_DisplayStringLine(Line5,(u8*)" LED : ON ");
}else
{
LCD_DisplayStringLine(Line5,(u8*)" LED : OFF ");
}
sprintf((char*)string," T : %.2d-%.2d-%.2d ",hour,min,sec);
LCD_DisplayStringLine(Line6, string);
sprintf((char*)string," %d",1);
LCD_DisplayStringLine(Line9, string);
}else
{
LCD_DisplayStringLine(Line3,(u8*)" setting ");
sprintf((char*)string," %.2d-%.2d-%.2d ",ALA_hour,ALA_min,ALA_sec);
LCD_DisplayStringLine(Line6, string);
sprintf((char*)string," %d",2);
LCD_DisplayStringLine(Line9, string);
}
ADC_val = Get_Adc() * 3.3 / 4096;
if((ADC_val > (3.3 * k)) && (B1_ALA_Flag) && (_200ms_flag)) // LED alarm
{
_200ms_flag = 0;
LED_MODE ^= (1<<8);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}else
{
LED_MODE |= (1<<8);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
void USART2_IRQHandler(void)
{
u8 temp = 0;
if(USART_GetITStatus(USART2, USART_IT_RXNE) == 1)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
temp = USART_ReceiveData(USART2);
if(temp == '\n')
{
RXCUNT = 0;
RXOVER = 1;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}else
{
RXBUF[RXCUNT] = temp;
RXCUNT++;
}
}
}
void RTC_IRQHandler(void)
{
u32 counter;
if(RTC_GetITStatus(RTC_IT_SEC) == 1)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_flag = 1;
RTC_WaitForLastTask();
counter = RTC_GetCounter();
RTC_WaitForLastTask();
if(counter == (23 * 3600 + 59 * 60 + 59))
{
RTC_SetCounter(0x0);
RTC_WaitForLastTask();
}
}
}
void SysTick_Handler(void)
{
static u8 key_sum = 0;
static u8 _200ms_sum = 0;
TimingDelay--;
if(++key_sum == 50) //50ms
{
key_sum = 0;
key_read_flag = 1;
}
if(++_200ms_sum == 200) // 200ms
{
_200ms_sum = 0;
_200ms_flag = 1;
}
}
#include "IO.h"
u16 LED_MODE = 0XFFFF;
u8 B1_ALA_Flag = 1;
u8 B2_Set_Flag = 0;
u8 ALA_hour = 0,ALA_min = 0,ALA_sec = 0;
u8 B3_Select_Flag = 0;
void USART2_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &USART_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
void USART2_SendString(u8 *str)
{
u8 index = 0;
do
{
USART_SendData(USART2, str[index]);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == 0);
index++;
}while(str[index] != 0);
}
void RTC_Init(u8 HH,u8 MM,u8 SS)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
RCC_LSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(40000 - 1);
RTC_WaitForLastTask();
RTC_SetCounter(HH * 3600 + MM * 60 + SS);
RTC_WaitForLastTask();
}
void ADC1_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
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_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
u16 Get_Adc(void)
{
ADC_RegularChannelConfig( ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC) == 0);
return ADC_GetConversionValue(ADC1);
}
void _24c02_Write(u8 address,u8 dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
u8 _24c02_Read(u8 address)
{
u8 dat;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
dat = I2CReceiveByte();
I2CWaitAck();
I2CStop();
return dat;
}
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = 0xff00;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}