蓝桥杯嵌入式速成
- cubmx创建工程
- 利用官方提供的LCD代码创建工程(15届不能用)
- 利用官方提供的LCD代码创建工程(15届能用)
- Keil配置
- 头文件注意
- 其他注意
- LED
- 闪烁
- 按键
- 短按
- 长按
- 双击
- LCD
- 高亮行
- 高亮字符
- RTC
- ADC
- I2C
- uart
- 接收
- 发送
- PWM
- DAC
- 定时器
- 捕获PWM频率+占空比
- 占空比
cubmx创建工程
利用官方提供的LCD代码创建工程(15届不能用)
利用官方提供的LCD代码创建工程(15届能用)
Keil配置
头文件注意
使用sprintf
需要加头文件stdio.h
使用memset
需要加头文件string.h
其他注意
如果要在main使用需要extern
uwTick
1ms加一次
Led 需要用LedDisp(0)
初始化
串口接收初始化HAL_UART_Receive_IT(&huart1,&rx_data,1);
串口不工作看中断是不是打开,引脚是不是PA9,PA10
PWM初始化HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);
输入捕获初始化HAL_TIM_IC_Start_IT(&htim16, TIM_CHANNEL_1);;
I2C 需要用I2CInit()
初始化
EEP开始需要第一次先写入题目要求的合法数据 之后再读
EEP 写0xa0
读(先写要读的地址) 0xa1
mcp 写0x5e
读0x5f
LED
Led初始化LedDisp(0)
void LED_disp(u8 led)
{HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET); //打开锁存器HAL_GPIO_WritePin(GPIOC,0xFF00,GPIO_PIN_SET); // set熄灭HAL_GPIO_WritePin(GPIOC,led<<8,GPIO_PIN_RESET); // reset点亮HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET); //关闭锁存器
}vu32 ledTick = 0;
u8 led = 0;
void LED_proc()
{if(uwTick - ledTick < 100) return; ledTick = uwTick;LED_disp(led);
}
闪烁
按键
u8 ko,kv,ku,kd = 0;void KeyRead()
{//5行四个按键if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == 0) kv = 1;else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == 0) kv = 2;else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == 0) kv = 3;else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == 0) kv = 4;else kv = 0;// 默认给值为0,这里别忘记了kd = kv &(ko ^ kv);ku = ~kv &(ko ^ kv);ko = kv;
}
短按
vu32 keyTick = 0;
void KeyProc()
{if(uwTick - keyTick < 20) return;keyTick =uwTick;KeyRead();if(kd == 1){}else if(kd == 2){}else if(kd == 3){}else if(kd == 4){}
长按
vu32 keyTick = 0;
vu32 keyLongTick = 0;
void KeyProc()
{if(uwTick - keyTick < 20) return;keyTick = uwTick;KeyRead();if(ku == 1) //注意用ku{//短按}else if(ku == 2 && (uwTick - keyLongTick < 800)) {//短按//注意要防止长按抬手触发短按多加了一个判断条件}else if(ku == 3 && (uwTick - keyLongTick < 800)){} else if(ku == 4 && (uwTick - keyLongTick < 800)){}else if(kd == 2 || kd == 3 || kd == 4){//开始长按计时keyLongTick = uwTick;}if(kv == 2 && (uwTick - keyLongTick > 800)){//长按操作}if(kv == 3 && (uwTick - keyLongTick > 800)){//长按操作}if(kv == 4 && (uwTick - keyLongTick > 800)){//长按操作}}
双击
u8 keyStatus;
u32 keyTick;
u32 keyIdle = 0;
u32 doubleTick = 0;
void Key_proc()
{if(uwTick - key_tick < 20) return;key_tick = uwTick;KEY_read();keyIdle = uwTick - doubleTick ;//2次按键间隔的时间,单位ms//之前没有按下if(kd == 1 && keyStatus == 0){keyStatus = 1;doubleTick = uwTick; //按下变为状态1,开始计时}else if(keyStatus == 1){//如果400ms内再按触发双击,如果第一次按后400ms没按则才触发单击,这里改为300ms也可以,我感觉有点快if(keyIdle < 400 && kd == 1) {//双击操作keyStatus = 0;}else if(key_idle > 400){//单击keyStatus= 0;}}
}
LCD
LCD最多21位
高亮行
if(pwm_line == 0)LCD_SetBackColor(Green);
sprintf((char *)lcd_buf," PA3_F:%-5dHz ",pa3_frq);
LCD_DisplayStringLine(Line2,lcd_buf);
LCD_SetBackColor(Black);if(pwm_line == 1)LCD_SetBackColor(Green);
sprintf((char *)lcd_buf," PA3_D:%d %% ",pa3_duty);
LCD_DisplayStringLine(Line3,lcd_buf);
LCD_SetBackColor(Black);
高亮字符
if(b2wz == 1 ) LCD_SetBackColor(Red);
LCD_DisplayChar(Line4,320-(4 * 16),times[ccwz].h/10+'0');
LCD_DisplayChar(Line4,320-(5 * 16),times[ccwz].h%10+'0');
LCD_SetBackColor(Blue);LCD_DisplayChar(Line4,320-(6 * 16),':');if(b2wz == 2) LCD_SetBackColor(Red);LCD_DisplayChar(Line4,320-(8 * 16),times[ccwz].m/10+'0');LCD_DisplayChar(Line4,320-(9 * 16),times[ccwz].m%10+'0');LCD_SetBackColor(Blue);LCD_DisplayChar(Line4,320-(10 * 16),':');if(b2wz == 3) LCD_SetBackColor(Red);
LCD_DisplayChar(Line4,320-(12 * 16),times[ccwz].s/10+'0');
LCD_DisplayChar(Line4,320-(13 * 16),times[ccwz].s%10+'0');
LCD_SetBackColor(Blue);
RTC
可以找例程
RTC_DateTypeDef D;
RTC_TimeTypeDef T;
u32 rtc_tick = 0;
void RTC_proc()
{if(uwTick - rtc_tick < 100)rtc_tick = uwTick;/* Get the RTC current Time */HAL_RTC_GetTime(&hrtc, &T, RTC_FORMAT_BIN);/* Get the RTC current Date */HAL_RTC_GetDate(&hrtc, &D, RTC_FORMAT_BIN);
}
ADC
如果双通道需要配置
采样时间选最大
u32 r37_value = 0;
u32 r38_value = 0;
u32 mcp_value = 0;
float r37_volt = 0;
float r38_volt = 0;
float mcp_volt = 0;
u32 adc_tick = 0;
void ADC_proc()
{if(uwTick - adc_tick < 100)return;adc_tick = uwTick;//就这两个函数HAL_ADC_Start(&hadc1);mcp_value = HAL_ADC_GetValue(&hadc1);HAL_ADC_Start(&hadc1);r38_value = HAL_ADC_GetValue(&hadc1);HAL_ADC_Start(&hadc2);r37_value = HAL_ADC_GetValue(&hadc2);r37_volt = r37_value * 3.3 / 4096.0;r38_volt = r38_value * 3.3 / 4096.0;mcp_volt = mcp_value * 3.3 / 4096.0; }
I2C
I2C 需要用I2CInit
初始化
//写9行
void EEpWrite(uint8_t addr,uint8_t data)
{I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(addr);I2CWaitAck();I2CSendByte(data);I2CWaitAck();I2CStop();HAL_Delay(5);
}
//读13行
uint8_t EEpRead(uint8_t add)
{uint8_t data;I2CStart();I2CSendByte(0xa0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStart();I2CSendByte(0xa1);I2CWaitAck();data = I2CReceiveByte();I2CSendNotAck(); //注意是noackI2CStop();return data;
}void MCP_write(uint8_t mcp)
{I2CStart();I2CSendByte(0x5E);I2CWaitAck();I2CSendByte(mcp);I2CWaitAck();I2CStop();
}
uart
接收
串口接收初始化HAL_UART_Receive_IT(&huart1,&rx_data,1);
接收中断3行
u8 rx_pointer , rx_data;
u8 rx_buff[30];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{rx_tick = uwTick;HAL_UART_Receive_IT(&huart1,&rx_data,1);rx_buff[rx_pointer++] = rx_data;
}
接收处理
u32 rx_tick = 0;
void RX_proc()
{if(uwTick - rx_tick < 50) return;rx_tick = uwTick;if(rx_pointer == 1 && rx_buff[0] == '#'){//接收输出正确}else if(rx_pointer > 0){//接收输出错误}rx_pointer = 0;memset(rx_buff,0,sizeof(rx_buff));
}
发送
#include <stdio.h>
struct __FILE
{int handle;/* Whatever you require here. If the only file you are using is *//* standard output using printf() for debugging, no file handling *//* is required. */
};
/* FILE is typedef’d in stdio.h. */
FILE __stdout;
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1,(u8 *)&ch,1,50);/* Your implementation of fputc(). */return ch;
}
然后就可以通过printf发送串口数据
PWM
不要用同一个定时器设置不同引脚的PWM
PWM初始化HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);
u16 pa3_frq = 1000;
u16 pa4_frq = 2000;
u8 pa3_duty = 50;
u8 pa4_duty = 50;
u32 pwm_tick = 0;
void PWM_proc()
{if(uwTick - pwm_tick < 100)return;pwm_tick = uwTick; __HAL_TIM_SetAutoreload(&htim2,1e6 / pa3_frq - 1);__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_4,(1e6 / pa3_frq) * pa3_duty / 100);__HAL_TIM_SetAutoreload(&htim3,1e6 / pa4_frq - 1);__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,1e6 / pa4_frq * pa4_duty / 100);
}
DAC
u16 dac_value = 0;
u32 dac_tick = 0;
void DAC_proc()
{if(uwTick - dac_tick < 100) return;dac_tick = uwTick;HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_2,DAC_ALIGN_12B_R,dac_value);HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);
}
定时器
定时器先配置定时时间 然后打开中断 然后打开定时器 即可
捕获PWM频率+占空比
PA15 -> R39
PA4 -> R40
打开列程
打开输出捕获中断
我们改成我们需要的
回调函数也复制过去
变量也复制过去
我们有俩个定时器所以要先判断一下
占空比