十一届蓝桥杯嵌入式省赛


title: 十一届蓝桥杯嵌入式省赛
date: 2021-12-04 15:49:03
tags: stm32
categories: 比赛项目

前言

由于本人乃菜鸡,而且这个项目只是我拿来给自己练习的,所以并没有想过做教学使用,大家可以参考一下,如果各位大佬垂阅,可以给出一下建议,我将不甚感激。

之前些32代码都是全部放到main.c里面,这次是第一次把主要的程序都放到其他.c中,然后调用,这样逻辑是会比较清晰的,而且以后和别人一起做项目,这样才能更好的分工和耦合,以及对接,但是我可能是因为第一次这样做吧,所以做的时候还是有点理不清,还需要进一步熟悉这种分模块的写法。

题目

分析

这一年的主观题还是比较简单的,主要难点在于如何发出两个PWM波,由于规定了PWM的输出引脚,所以如果使用定时器来产生PWM波,不太好搞,生成不一样频率的PWM,然而如果使用软件模拟PWM的话,就比较简单了。

ow4LPx.jpg

代码

1.主函数模块

main.c

#include "stm32f10x.h"
#include "lcd.h"
#include "UI.h"
#include "key.h"
#include "stdio.h"
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);
extern int duty1,duty2;
int main(void)
{
	SysTick_Config(SystemCoreClock/100000);	//一次中断10us,1khz是1ms100个中断,2khz是200个中断
	Key_init();
	Led_init();
	Led_all_close();
	ADC_Config();
	STM3210B_LCD_Init();
	LCD_Clear(White);
	LCD_SetBackColor(White);
	LCD_SetTextColor(Black);
	while(1){
	Key_Set();										//按键控制PWM
	UUII();											  //LCD显示
    }}
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

2.显示和adc配置模块

adc.c

#include "lcd.h"
#include "UI.h"
#include "stdio.h"
#include "stm32f10x.h"
#include "key.h"
char read[9];
int ADC_Flag;
extern int flag_key_1;
extern int flag_key_4;
int Mode;
int UI_q;					//切换数据显示或者参数显示
int duty1,duty2;

void UUII(){
	if(flag_key_1%2 == 0){
		if((flag_key_4%2 ==0)){
		LCD_DisplayStringLine(Line0,(unsigned char *)"        Data");
				sprintf((char*)read,"      V: %.2fv",Read_ADC()*3.3/100);
		LCD_DisplayStringLine(Line3,(unsigned char *)read);
		LCD_DisplayStringLine(Line6,(unsigned char *)"      Mode: AUTO");
		
		duty1=(int)Read_ADC();
		duty2=(int)Read_ADC();		//现在的adc输出的是真实电压的10/3.3倍,所以可以可以直接赋值
			
			
				Led_all_close();
				GPIO_ResetBits(GPIOC,GPIO_Pin_8);
				GPIO_SetBits(GPIOD,GPIO_Pin_2);
        GPIO_ResetBits(GPIOD,GPIO_Pin_2); 
		}
		else{
		LCD_DisplayStringLine(Line0,(unsigned char *)"        Data");
		sprintf((char*)read,"      V: %.2fv",Read_ADC()*3.3/100);
		LCD_DisplayStringLine(Line3,(unsigned char *)read);
		LCD_DisplayStringLine(Line6,(unsigned char *)"      Mode: MANU");
			
				Led_all_close();
				GPIO_ResetBits(GPIOC,GPIO_Pin_9);
				GPIO_SetBits(GPIOD,GPIO_Pin_2);
        GPIO_ResetBits(GPIOD,GPIO_Pin_2); 
	
			
		}
		UI_q=0;
	}
	else{
		if((flag_key_4%2 ==0)){							//自动模式
			
		duty1=(int)Read_ADC();
		duty2=(int)Read_ADC();
				
		}
		else{																//手动模式
		if(RB2 == KEY_ON){
		LCD_Clear(White);
		duty1=duty1+10;
		if(duty1>90){duty1=0;}
			
	
	}	
		if(RB3 == KEY_ON){
		LCD_Clear(White);
		duty2=duty2+10;
			if(duty2>90){duty2=0;}
	}	
		
			
		}
		LCD_DisplayStringLine(Line0,(unsigned char *)"        Para");
		sprintf((char*)read,"        PA6:%d   ",duty1);
		LCD_DisplayStringLine(Line3,(unsigned char *)read);
		sprintf((char*)read,"        PA7:%d   ",duty2);
		LCD_DisplayStringLine(Line6,(unsigned char *)read);
		UI_q=1;}
	if(UI_q == 0){	
	
	}
	
	
}

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


void ADC_Config(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);
	
	// 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_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));
}

3、按键&LED配置

#include "key.h"
#include "stm32f10x.h"
#include "lcd.h"
int flag_key_1;
int flag_key_4;

uint16_t Channel2Pulse = 0, Channel3Pulse = 0;

void Key_init(){
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
		//B1、B2按键引脚配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8; // 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    //B3、B4按键引脚配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);	
}

uint16_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON)
	{
		while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
		return KEY_ON;
	}
	else
		return KEY_OFF;
}

void Key_Set(void){
	if(RB1 == KEY_ON){
	LCD_Clear(White);
	flag_key_1++;
	
	}
	
	if(RB4 == KEY_ON){
	LCD_Clear(White);
	flag_key_4++;
	
	}
	

}
void Led_init(void){
		GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
		//LED引脚配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15; // 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    //锁存器引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

}				

void Led_all_close(){
	   GPIO_SetBits(GPIOC,GPIO_Pin_8| GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15);
	   GPIO_SetBits(GPIOD,GPIO_Pin_2);
        GPIO_ResetBits(GPIOD,GPIO_Pin_2); 
}

4、systick中断模拟PWM

分频比

首先设置systick中断函数多久发送的周期,这个函数的形参数,是分频比

SysTick_Config(SystemCoreClock/100000);

中 断 频 率 = 主 频 率 / 分 频 比 中断频率=主频率/分频比 =/

$$
=SystemCoreClock / (SystemCoreClock/100000)

=100000HZ

T=10us
$$

这样题目需要的1KHZ,即周期为1ms的PWM,和走起为500us的PWM就都能得到了。

中断函数

#include "stm32f10x_it.h"
int cnt1,cnt2;
extern u32 TimingDelay;
	extern int duty1,duty2;
void SysTick_Handler(void)
{	cnt1++;
	cnt2++;
	TimingDelay--;
	if(cnt1<duty1){
		GPIO_SetBits(GPIOA,GPIO_Pin_6);

}
	if(cnt1>duty1){
		GPIO_ResetBits(GPIOA,GPIO_Pin_6);

}
	if(cnt1==100){
		cnt1=0;}
	
	if(cnt2<(duty2/2)){

		GPIO_SetBits(GPIOA,GPIO_Pin_7);
}
	if(cnt2>(duty2/2)){

		GPIO_ResetBits(GPIOA,GPIO_Pin_7);
}
	if(cnt2==50){
		cnt2=0;}
}

结果

初始状态

owHDMV.md.jpg

owH5M6.md.jpg

波形

owbZQ0.md.jpg

总结:

这次的题目还是比较简单的,难点就在与如何产生两个不同频率的PWM,如果只想到定时器产生PWM的话,由于题目规定的两个PWM的引脚是同一个定时器的两个端口,所以要设置成不同频率还是有点难度的,但如果软件模拟PWM,还是比较简单的。除此之外,这道题几乎没有难度,个人需要提升的点在于:需要行一步熟悉各个模块的配置过程。因为在正式比赛的时候是没有例程给你使用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值