设计一个电压测量监控设备,定时通过串口向 PC 机发送电压值,通过串口接收系统配
置参数并保存到 E2PROM 中。设备硬件部分主要由电源部分、控制器单元、串口部分、存储
单元组成,系统框图如图 1 所示:
设计任务及要求
图 2. LCD 显示界面(参考)
图 3. 定时上报时间设置界面(参考)
(1)确定需要使用的模块
本题需要使用如下模块
LED模块
按键模块
ADC模块
RTC模块
LCD模块
USART模块
I2C模块
分别把它们初始化
(2)编写各模块的功能实现函数
如:Key_Read( )函数实现按键功能
Read_ADC()函数获得模拟输入值
USART2_SendString()函数用来向串口2传输数据
(3)显示函数的编写
(4)查缺补漏
模块初始化
这个不必多说了,相信大家已经写的滚瓜烂熟了。看代码:
#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define KEY3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define KEY4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)
#define HH 23
#define MM 59
#define SS 54
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0xff00;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIOC->ODR=0xff00;
GPIOD->ODR|=(1<<2);
GPIOD->ODR&=~(1<<2);
}
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void ADC1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode=DISABLE;
ADC_InitStructure.ADC_NbrOfChannel=1;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_239Cycles5);
ADC_Cmd(ADC1,ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
void USART2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2,&USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2,ENABLE);
}
void _24c02_Write(u8 adress,u8 data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(adress);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
u8 _24c02_Read(u8 adress)
{
u8 temp;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(adress);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
temp=I2CReceiveByte();
I2CWaitAck();
I2CStop();
return temp;
}
void RTC_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
RCC_LSICmd(ENABLE);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
NVIC_InitStructure.NVIC_IRQChannel=RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(40000);
RTC_WaitForLastTask();
RTC_SetCounter(3600*23+60*59+SS);
RTC_WaitForLastTask();
}
编写各模块的功能实现函数
u8 LED_Status=1;//LED1状态默认打开
u8 Set_Flag; //主界面与设置界面切换标志
u8 Change_Flag=1;//RTC时分秒高显标志
u8 System_Flag=0;
u8 hour_f;
u8 min_f;
u8 sec_f;
u32 times_f;
float READ_ADC(void)
{
float temp;
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
Delay_Ms(5);
temp=ADC_GetConversionValue(ADC1)*3.30/0xfff;
return temp;
}
void USART2_SendString(u8 *str)
{
u8 index=0;
do
{
USART_SendData(USART2,str[index]);
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)!=SET);
index++;
}while(str[index]!=0);
}
void KEY_Read(void)
{
static u8 Key1_Num=0,Key2_Num=0,Key3_Num=0,Key4_Num=0;
if(KEY1==0)
{
Key1_Num++;
if(Key1_Num==1)
{
LED_Status^=1;
}
}else{
Key1_Num=0;
}
if(KEY2==0)
{
Key2_Num++;
if(Key2_Num==1)
{
Set_Flag^=1;
if(System_Flag==1)
{
System_Flag=0;
times_f=hour_f*3600+min_f*60+sec_f;
RTC_SetCounter(times_f);
RTC_WaitForLastTask();
}
LCD_ClearLine(Line2);
LCD_ClearLine(Line4);
LCD_ClearLine(Line6);
LCD_ClearLine(Line8);
}
}else{
Key2_Num=0;
}
if(KEY3==0)
{
Key3_Num++;
if(Key3_Num==1)
{
Change_Flag++;
if(Change_Flag>3){
Change_Flag=1;}
}
}else{
Key3_Num=0;
}
if(KEY4==0)
{
Key4_Num++;
if(Key4_Num==1)
{
switch(Change_Flag)
{
case 1: hour_f++;if(hour_f>23) hour_f=0;
break;
case 2: min_f++;if(min_f>59) min_f=0;
break;
case 3: sec_f++;if(sec_f>59) sec_f=0;
break;
}
System_Flag=1;
}
}else{
Key4_Num=0;
}
}
stm32f10x_it.c 各类中断函数编写
extern u32 TimingDelay;
extern u8 LED_Flag;
extern u8 KEY_Flag;
extern u8 ADC_Flag;
extern u8 Display_Flag;
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
temp=USART_ReceiveData(USART2);
if(temp=='\n')
{
RXCOUNT=0;
RXOVER=1;
}else{
RXBUF[RXCOUNT++]=temp;
}
}
}
void RTC_IRQHandler(void)
{
u32 times;
if(RTC_GetITStatus(RTC_IT_SEC)==SET)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_Flag=1;
times=RTC_GetCounter();
if(times==24*3600-1)
{
RTC_SetCounter(0x0);
}
}
}
void SysTick_Handler(void)
{
static u8 LED_Sum=0;
static u8 KEY_Sum=0;
static u8 ADC_Sum=0;
static u8 Display_Sum=0;
TimingDelay--;
if(++ADC_Sum==200)
{
ADC_Sum=0;
ADC_Flag=1;
}
if(++KEY_Sum==50)
{
KEY_Sum=0;
KEY_Flag=1;
}
if(++Display_Sum==50)
{
Display_Sum=0;
Display_Flag=1;
}
if(++LED_Sum==200)
{
LED_Sum=0;
LED_Flag=1;
}
}
最后就是主函数的编写(重中之重)
u8 RTC_Flag=0;
u8 LED_Flag=0;
u8 KEY_Flag=0;
u8 ADC_Flag=0;
u8 Display_Flag=0;
int k;
int main(void)
{
float temp;
u16 LED_MODE=0xff00;
u8 string[20];
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
LED_Init();
KEY_Init();
USART2_Init();
ADC1_Init();
RTC_Init();
SysTick_Config(SystemCoreClock/1000);
i2c_init();
Delay_Ms(200);
if(_24c02_Read(0x11)!=5)
{
_24c02_Write(0x11,5);
Delay_Ms(5);
_24c02_Write(0x21,1);
Delay_Ms(5);
}
k=(int)_24c02_Read(0x21);
Delay_Ms(5);
while(1)
{
if(RXOVER)
{
RXOVER=0;
if(RXBUF[0]=='k'&&(RXBUF[3]>'1'&&RXBUF[3]<'9'))
{
k=RXBUF[3]-0x30;
USART2_SendString("OK\r\n");
_24c02_Write(0x21,k);
}
}
if(RTC_Flag)
{
RTC_Flag=0;
times=RTC_GetCounter();
hour=times/3600;
min=times%3600/60;
sec=times%3600%60;
if(hour==0&&min==0&&sec==0)
{
sprintf((char*)string,"%.2fV+0.%d+%.2d%.2d%.2d\n",temp,k,hour,min,sec);
USART2_SendString(string);
}
}
if(ADC_Flag)
{
ADC_Flag=0;
temp=READ_ADC();
}
if(LED_Flag)
{
LED_Flag=0;
if(LED_Status)
{
if(temp>(float)3.3*k/10)
{
LED_MODE^=(1<<8);
}else{
LED_MODE|=(1<<8);
}
GPIOC->ODR=LED_MODE;
GPIOD->ODR|=(1<<2);
GPIOD->ODR&=~(1<<2);
}else{
GPIOC->ODR=0xff00;
GPIOD->ODR|=(1<<2);
GPIOD->ODR&=~(1<<2);
}
}
if(KEY_Flag)
{
KEY_Flag=0;
KEY_Read();
}
if(Display_Flag)
{
Display_Flag=0;
if(Set_Flag==0)
{
sprintf((char*)string," V1:%.2fV",temp);
LCD_DisplayStringLine(Line2,string);
sprintf((char*)string," k:0.%d",k);
LCD_DisplayStringLine(Line4,string);
if(LED_Status)
{
sprintf((char*)string," LED: ON");
}else{
sprintf((char*)string," LED:OFF");
}
LCD_DisplayStringLine(Line6,string);
sprintf((char*)string," %.2d:%.2d:%.2d",hour,min,sec);
LCD_DisplayStringLine(Line8,string);
sprintf((char*)string," 1");
LCD_DisplayStringLine(Line9,string);
}else if(Set_Flag==1)
{
sprintf((char*)string," Settings");
LCD_DisplayStringLine(Line2,string);
if(Change_Flag==1)
{
LCD_SetTextColor(Red);
}else{
LCD_SetTextColor(White);
}
LCD_DisplayChar(Line4,270,hour_f/10+0x30);
LCD_DisplayChar(Line4,255,hour_f%10+0x30);
LCD_SetTextColor(White);
LCD_DisplayChar(Line4,240,'-');
if(Change_Flag==2)
{
LCD_SetTextColor(Red);
}else{
LCD_SetTextColor(White);
}
LCD_DisplayChar(Line4,225,min_f/10+0x30);
LCD_DisplayChar(Line4,210,min_f%10+0x30);
LCD_SetTextColor(White);
LCD_DisplayChar(Line4,195,'-');
if(Change_Flag==3)
{
LCD_SetTextColor(Red);
}else{
LCD_SetTextColor(White);
}
LCD_DisplayChar(Line4,180,sec_f/10+0x30);
LCD_DisplayChar(Line4,165,sec_f%10+0x30);
LCD_SetTextColor(White);
sprintf((char*)string," 2");
LCD_DisplayStringLine(Line9,string);
}
}
}
}
本文除标注写在stm32f10x_it.c中的文件,其余全部在main.c中
关于I2C为什么要这样设置,可以看我的这篇博客
蓝桥杯嵌入式I2C使用EEPROM教程(内附初始值设定)
亲测实现
蓝桥杯嵌入式第七届模拟题-电压测量监控系统
蓝桥杯嵌入式第十届省赛题代码
蓝桥杯嵌入式第十一届省赛模拟题
有收获?希望老铁们来个三连击,给更多的同学看到这篇文章
给大力点个赞呗,可以让更多的人看到这篇文章,顺便激励下我,嘻嘻!
有不懂的可以私信我呦!