蓝桥杯嵌入式学习(cubemxkeil5)
目录
一、LED
二、KEY
三、ADC
四、PWM
五、IC
六、IC(测量占空比)
七、UART
八、I2C
九、RTC
十、 RTC闹钟
一、LED
引脚PC8~PC15,默认高电平(灭)。
此外还要配置PD2为输出引脚(控制LED锁存) ,默认低电平(锁住)!!!
#include "led.h"void led_disp(unsigned char disp_led)
{HAL_GPIO_WritePin(GPIOC,GPIO_PIN_ALL,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,disp_led<<8,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}/*使用方法*/
unsigned char ledon=0x00;
led_disp(ledon|=0x01);//第一个led亮
led_disp(ledon|=0x04);//第三个led亮led_disp(ledon&=~(0x01))//第一个led灭
led_disp(ledon&=~(0x08))//第四个led灭
二、KEY
选择PB0~PB2,PA0为输入模式,配置成上拉输入。 我们按键用的是定时器轮询检测按键状态(还能实现长按短按的功能)。
时钟源选择内部时钟,设置成100Hz,也就是10ms进一次中断,别忘了在NVIC Settings打勾 !
#include "intterrupt.h"struct keys
{unsigned char sta;//引脚电平unsigned char flag;//是否按下unsigned char longflag;//是否长按unsigned char judge;//进度标志位unsigned int time;//长按时要用到
};
struct keys key[4]={0,0,0};void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIMX){key[0].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(int i=0;i<4;i++){switch(key[i].judge){case 0:{if(key[i].sta==0){key[i].judge=1;key[i].time=0;}}break;case 1:{if(key[i].sta==0){key[i].judge=2;}else{key[i].judge=0;}}break;case 2:{if(key[i].sta==1)//松手的时候根据time来判断长短按{key[i].judge=0;if(key[i].time<200)//小于2s{key[i].flag=1;}}else//没松手{key[i].time++;if(key[i].time>200)//大于2s{key[i].longflag=1;}}}break;}}}
}/*使用方法*/void key_proc(void)
{if(key[0].flag==1)//按键1短按{//处理数据key[0].flag=0;}if(key[3].longflag==1)//按键4长按{//处理数据key[3].longflag=0;}
}
key_proc()丢while里。
三、ADC
板子从左往右数第一个是PB15引脚(对应ADC2的通道15),第二个是PB12引脚(对应ADC1的通道11),采样周期选到最大,一定程度上能防止adc一直抖动。
#include "myadc.h"double adc_get(ADC_HandleTypeDef *pin)
{unsigned int adc;HAL_ADC_Start(pin);adc=HAL_ADC_GetValue(pin);//HAL_Delay(1);可不加return adc*3.3/4096;
}/*使用方法*/
adc_get(&hadc2);//获取第一个电压
adc_get(&hadc1);//获取第二个电压
四、PWM
假设题目要求我们在PA7引脚输出频率为1000Hz,占空比为50%的PWM波
注意所选定时器最好不要和按键中断的定时器共用 !
frq=80000000/800/100;duty=50/100;
//在while之前启动PWM
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);/*设置占空比和频率*/
__HAL_TIM_SET_PRESCALER(&htim17,80000000/100/PWM_frq);//设置频率__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,duty);//设置占空比
五、IC
PB4和PA15引脚用于输入捕获,测量频率。最好用TIM2和TIM3! 按键定时器等所有外设都设置好了再设置。
#include "intterrupt.h"unsigned int ccrl_val=0;
unsigned int frq=0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM2){ccrl_val=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);__HAL_TIM_SetCounter(htim,0);frq=(80000000/80)/ccrl_val;HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1);}//if(htim->Instance==TIM3)//{// //}//同上 再定义一个变量即可 注意在main里extern frq
}/*使用方法*/
//在while之前启动IC 就可以在while里读frq
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);//启动第一个IC
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);//启动第二个IC
六、IC(测量占空比)
假设题目要求我们检测PA7引脚输入的信号的占空比
cubemx如上配置,PA7对应TIM3的通道二,那么把通道二设置成直接模式,另外选一个通道设置成间接模式,让直接模式测量上升沿,间接模式测量下降沿。
#include "intterrupt.h"unsigned int ccrl_vala=0,ccrl_valb=0;
unsigned int frq=0;
double duty=0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==TIM3){ccrl_vala=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);//直接ccrl_valb=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//间接__HAL_TIM_SetCounter(htim,0);frq=(80000000/80)/ccrl_vala;duty=(double)(ccrl_valb/ccrl_vala)*100;HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_2);}
}
这个看看就好 考的几率不大。
七、UART
记得手动选择PA9和PA10,波特率按题目要求,一般是9600。记得开中断!!!
#include "interrupt.h"
#include "usart.h"char rxdata[22];
unsigned char rxbit;
unsigned char rx_p;void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{rxdata[rx_p++]=rxbit;HAL_UART_Receive_IT(&huart1,&rxbit,1);
}/*使用方法*/
include "string.h"//使用memset函数
//在while之前初始化 调用HAL_UART_Receive_IT(&huart1,&rxbit,1);void uart_proc(void)
{if(rx_p>0){if(rx_p==x)//实际要接收的位数{//处理}else{//报错}rx_p=0;memset(rxdata,0,22);//22要和你设置的rxdata长度一样}
}/*注意事项*/
//在while循环里这样写 防止接收不完整
while(1)
{if(rx_p!=0){uint8_t temp=rx_p;HAL_Delay(1);if(rx_p==temp){uart_proc();}}
}
八、I2C
直接在官方给的i2c_hal.c里写,cubemxPB6和PB7直接选择输出模式。
#include "i2c_hal.h"//官方的.c函数void eeprom_write(unsigned char addr,unsigned char dat)
{I2CStart();I2CSendByte(0xa0);//0表示写I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CSendByte(dat);I2CWaitAck();I2CStop();
}unsigned char eeprom_read(unsigned char addr)
{unsigned char dat;I2CStart();I2CSendByte(0xa0);//0表示写I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0xa1);//1是读I2CWaitAck();dat=I2CReceiveByte();I2CSendNotAck();//读出来之后发送非应答I2CStop();return dat;
}/*使用方法*/
eeprom_write(0,data);//地址从0开始,存八位的数据。data=eeprom(0);//读地址
八位无符号整型数据可以直接写和读,double类型的参考下图;
注意:每次写入都要延时5ms!!!
九、RTC
近几年基本不考,但要会最基本的rtc时钟。参数填125和6000。
#include "stdio.h"RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;while(1)
{HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN);//一定要先获取时间再获取日期!!!HAL_RTC_GetDate(&hrtc,&sDate,RTC_FORMAT_BIN);char text[50];sprintf(text,"%02d:%02d:%02d--%02d:%02d:%02d",sDate.Year,sDate.Month,sDate.Date,sTime.Hours,sTime.Minutes,sTime.Seconds);//再用官方提供的lcd显示函数显示年月日时分秒即可
}
RTC暂停:__HAL_RCC_RTC_DISABLE();
RTC恢复:__HAL_RCC_RTC_ENABLE();
十、 RTC闹钟
记得开中断,闹钟先设置成3s后
RTC_AlarmTypeDef sAlarm;void GET_Time(void)
{HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
}void SET_alarm(void)
{sAlarm.AlarmTime.Hours = 0x00;sAlarm.AlarmTime.Minutes = 0x0;
/**/sAlarm.AlarmTime.Seconds = sTime.Seconds+1;sAlarm.AlarmTime.SubSeconds = 0x0;sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES;sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;sAlarm.AlarmDateWeekDay = 0x1;sAlarm.Alarm = RTC_ALARM_A;
/**/if(sAlarm.AlarmTime.Seconds==60)sAlarm.AlarmTime.Seconds=0;
/**/HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);//这里要注意,我们选择的是十进制
}//中断服务函数
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{GET_Time();SET_Alarm();//操作
}
SET_alarm里加了多行注释的是自己添加的东西,其余从rtc.c复制
每一秒进一次rtc闹钟的回调函数,在回调函数里进行对应的操作即可。
(可能不考,了解即可)