蓝桥杯嵌入式第六届省赛——“电压测量监控设备”旧版标准库

6 篇文章 0 订阅
6 篇文章 0 订阅

一、赛题分析

        对于本届赛题,涉及模块不多,相对简短。主要难度集中在USART、E2PROM上。对于串口接收数据,当数据接收到时,要及时对接收数组清0,否则会影响下次串口接收。对于E2PROM的存储功能,只需要在串口接收完毕之后写入一次,再在while(1)之前读取一次即可掉电保护。

二、程序设计

        IIC、LED、KEY、USART等初始化均可在上一篇文章找到:

蓝桥杯嵌入式——第四届省赛“双路输出控制器”旧板标准库_对愁眠后霜满天的博客-CSDN博客

        或在文章最后附上的链接处下载工程。

1、ADC初始化

#ifndef __ADC_H
#define __ADC_H

#include "stm32f10x.h"
#include "stdio.h"

void ADC_INIT(void);
float Read_ADC(void);

#endif


#include "adc.h"
#include "delay.h"
#include "stm32f10x_adc.h"

void ADC_INIT(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  ADC_InitTypeDef ADC_InitStructure;
		
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  //PB0-ADC channel 8
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
		
  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_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);    

  ADC_Cmd(ADC1, ENABLE);   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
}

float Read_ADC(void)
{
  float ADC_VALUE;
	
  ADC_SoftwareStartConvCmd(ADC1,ENABLE);
  Delay_Ms(5);
  ADC_VALUE = ADC_GetConversionValue(ADC1)*3.30/0xfff;
	
  return ADC_VALUE;
}

        在stm32f10x_it.c中用系统滴答定时器延时ADC采集,做到200ms更新一次数据。只需要在主函数中将ADC_Flag置0,读取Read_ADC即可。

extern u32 TimingDelay;
extern u8 ADC_Flag;
u8 Ms = 0;

void SysTick_Handler(void)
{
  TimingDelay--;
  if(++Ms == 200){
    Ms = 0;
    ADC_Flag = 1;
  }
}

2、USART部分改动

        由输入格式“k0.1\n”即可知道,当USART_RXBUF[5] == 'n'时可判断串口接收完毕。当k得到幅值时,USART_RXBUF要清0,否则多次发送则会出错。在此串口接收到的数据为字符形式,减去48即可得到对应数字。

void usart_port(void)
{
  if(RXOVER == 1)
  {
    RXOVER = 0;
    RXCUNT = 0;
    k = USART_RXBUF[3] - 48;
    i2c_write(0x60,(u8)k);Delay_Ms(10); //i2c写入
    USART_SendString(USART2,(u8*)"ok\\n\r\n"); //返回ok
    memset(USART_RXBUF,0,sizeof(USART_RXBUF)); //USART_RXBUF清0
  }
	
  if(_h == a.hou&&_m == a.min&&_s == a.sec&&send_flag == 0)//报警功能实现处
  {
    send_flag = 1;
    memset(string,0,sizeof(string));
    sprintf((char*)string,"%.2f+%.1f+%02d%02d%02d\\n\r\n",adc_temp,k/10,_h,_m,_s);	
    USART_SendString(USART2,string);
  }
}

3.main.c主程序

        程序编写浅显易懂,不做过多分析。个别处以在代码中做出注释。

#include "stm32f10x.h"
#include "lcd.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "rtc.h"
#include "adc.h"
#include "usart.h"
#include "timer.h"
#include "i2c.h"
#include "stdio.h"
#include "string.h"

struct alarm_time{u8 hou,min,sec;}a={0,0,0};
enum LED_STAT{OFF,ON};
enum SHOW_STAT{MAIN,SETTING};

u8 show_flag = MAIN,off_on_flag = OFF;
u8 key_flag = 0,ADC_Flag,led_flag = 0,select_flag = 0,send_flag = 0;
u8 string[20];
u8 temp1 = 6,temp2 = 7;
float adc_temp,k = 1;

void key_in(void);
void show_lcd(void);
void highlight_char(u8 Line, u8 *ptr);
void usart_port(void);
void led_shine(void);

//Main Body
int main(void)
{
  STM3210B_LCD_Init();     
  LCD_Clear(Black);          
  LCD_SetBackColor(Black);   
  LCD_SetTextColor(White);  
  SysTick_Config(SystemCoreClock/1000);
	
  TIM4_Init();
  LED_Init();
  KEY_Init();
  ADC_INIT();
  i2c_init();
  USART2_Init(9600);
  RTC_Init(23,59,55);
	
  k = i2c_read(0x60);
  if(k>10||k==0)k=1;
  while(1)
  {
    update_time();
    show_lcd();
    key_in();
    usart_port();
    led_shine();
  }
}

void key_in(void)
{
  key_flag = key_scan();
  if(key_flag == 1)
  {
    off_on_flag =! off_on_flag;
  }

  if(key_flag == 2)
  {
    show_flag =! show_flag;
    select_flag = 0;
    send_flag = 0;
    temp1 = 6;temp2 = 7;
    LCD_Clear(Black);
  }

  if(key_flag == 3 && show_flag == SETTING)//改变高光系数
  {
    select_flag = (select_flag + 1) % 3;
    if(select_flag == 0){temp1 = 6;temp2 = 7;}
    if(select_flag == 1){temp1 = 9;temp2 = 10;}
    if(select_flag == 2){temp1 = 12;temp2 = 13;}
  }

  if(key_flag == 4 && show_flag == SETTING)//改变定时上报时间
  {
    if(select_flag == 0)a.hou = (a.hou + 1) % 24;
    if(select_flag == 1)a.min = (a.min + 1) % 60;
    if(select_flag == 2)a.sec = (a.sec + 1) % 60;
  }
}

void show_lcd(void)
{
  if(show_flag == MAIN)
  {
    if(ADC_Flag)
    {
      ADC_Flag = 0;
      adc_temp = Read_ADC();
      memset(string,0,sizeof(string));
      sprintf((char*)string,"   V1:%.2fV    ",adc_temp);
      LCD_DisplayStringLine(Line1,string);
    }
		
    memset(string,0,sizeof(string));
    sprintf((char*)string,"    k:%.1f    ",k/10);
    LCD_DisplayStringLine(Line3,string);
		
    switch(off_on_flag)
    {
      case OFF: LCD_DisplayStringLine(Line5,(u8*)"  LED:OFF  ");break;
      case ON : LCD_DisplayStringLine(Line5,(u8*)"  LED:ON  ");break;
      default : break;
    }
		
    LCD_DisplayStringLine(Line7,(u8*)time_str);
		
    LCD_DisplayStringLine(Line9,(u8*)"                 1");
  }
	
  if(show_flag == SETTING)
  {
    LCD_DisplayStringLine(Line1,(u8*)"      Setting      ");		
		
    memset(string,0,sizeof(string));
    sprintf((char*)string,"      %02d-%02d-%02d      ",a.hou,a.min,a.sec);		
    highlight_char(Line4,string);
		
    LCD_DisplayStringLine(Line9,(u8*)"                 2");
  }
}

/*
字体高光函数,只需要改变temp1、temp2即可改变高光位置。
*/
void highlight_char(u8 Line, u8 *ptr)
{
  u32 i = 0;
  u16 refcolumn = 319;
  while ((*ptr != 0) && (i < 20))
  {
    if(i == temp1 || i == temp2)
    {
      LCD_SetTextColor(Yellow);
    }
    LCD_DisplayChar(Line, refcolumn, *ptr);
    LCD_SetTextColor(White);
    refcolumn -= 16;
    ptr++;
    i++;
  }
}

void usart_port(void)
{
  if(RXOVER == 1)
  {
    RXOVER = 0;
    RXCUNT = 0;
    k = USART_RXBUF[3] - 48;
    i2c_write(0x60,(u8)k);Delay_Ms(10); //i2c写入
    USART_SendString(USART2,(u8*)"ok\\n\r\n"); //返回ok
    memset(USART_RXBUF,0,sizeof(USART_RXBUF)); //USART_RXBUF清0
  }
	
  if(_h == a.hou&&_m == a.min&&_s == a.sec&&send_flag == 0)//报警功能实现处
  {
    send_flag = 1;
    memset(string,0,sizeof(string));
    sprintf((char*)string,"%.2f+%.1f+%02d%02d%02d\\n\r\n",adc_temp,k/10,_h,_m,_s);	
    USART_SendString(USART2,string);
  }
}

//报警函数
void led_shine(void)
{
  if(off_on_flag == OFF&&show_flag == MAIN)
  {
    if(adc_temp>3.3*k/10)LED_Control(LED1,led_flag);
    else LED_Control(LED1,0);
  }
  else LED_Control(LED1,0);
}

void TIM4_IRQHandler(void)
{
  static u16 led_cnt = 0;
  if(TIM_GetITStatus(TIM4,TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
    if(++led_cnt>=200)
    {
      led_cnt = 0;
      led_flag =! led_flag;
    }
  }
}

三、附上工程

链接:https://pan.baidu.com/s/1Jw4MTK2QQ26_SDN8qNiBNw 
提取码:kcgi

有不对的地方,请多指教...

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

对愁眠后霜满天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值