笔者也是不得不要来做一做蓝桥了啊,希望到时候评测机器没有乱七八糟的毛病(4T给孩子测得害怕了)
初始化:
System Core->RCC->HSE配置晶振Crystal/Ceramic Resonator
SYS->Debug配置Serial Wire
时钟配置:输入晶振频率24M,用HSE主频80M
工程配置:IDE用MDK-ARM,勾选生成独立.c和.h文件
main.h里typedef uint unsigned int 和typedef uchar unsigned char
LCD:
cubemx
PA8,PB5,8,9以及PC0-15配置成GPIO_Output(也可以不配置,官方文件带初始化)
keil
copy过来lcd.h、lcd.c、font.h到自己的新建目录下
while开始前
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);显示字符
#include <stdio.h>
char text[20];
sprintf(text," xxxx ");
LCD_DsiplayStringLine(Line0,(unsigned char *)text);//注意这里用unsigned char *和uint8_t *等价(typedef unsigned char uint8_t;)LED:
cubemx
PC8-15配置成GPIO_Output,GPIO output level设置为high
PD2配置成GPIO_Output
keil
建议新建led.c和.h
led.h
#ifndef _LED_H_
#define _LED_H_
#include "main.h"
void led_disp(uint led_num,uint led);
#endifled.c
#include "led.h"
static uint led_sta=0x00;
void led_disp(uint led_num,uint led){
if(led==1){
led_sta |= 1<<led_num;
}
else{
led_sta &= ~(1<<led_num);
}
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_ALL,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,led_sta,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);//PD2是锁存控制器,低电平锁定
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}KEY:
cubemx
PB0,1,2以及PA0配置GPIO_Input,Pull-up上拉模式
任意开一个定时器,内部时钟,100Hz,根据是否是高级定时器开启全局中断/更新中断
keil
建议新建interrupt.c和.h
由于涉及到定时器中断,while前要加
HAL_TIM_Start_IT(&htim4);interrupt.h
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
#include "main.h"
#include "stdbool.h"
struct key{
uint jud;
bool sign;
bool long;//应用双击时为bool dou;
bool sta;
uint time;
}
void HAL_TIM_PeriodElaspsedCallback(TIM_HandleTypeDef *htim);
#endifinterrupt.c(长短按版)
#include "interrupt.h"
struct key keys[4]={0,0,0,0,0};
void HAL_TIM_PeriodElaspsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM4){
keys[0].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
keys[1].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
keys[2].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
keys[3].sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++){
switch(keys[i].jud){
case 0:{
if(keys[i].sta==0){
keys[i].jud=1;
keys[i].time=0;
}
break;
}
case 1:{
if(keys[i].sta==0){
keys[i].jud=2;
}
else
keys[i].jud=0;
break;
}
case 2:{
if(keys[i].sta==1){
if(keys[i].time<100){
keys[i].sign=1;
}
keys[i].jud=0;
}
else{
keys[i].time++;
if(keys[i].time>=100){
keys[i].long=1;
}
}
break;
}
}
}
}
}interrupt.c(单双击版)
#include "interrupt.h"
struct key keys[4]={0,0,0,0,0};
static int last_key=0;
uint validity=0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM4){
keys[0].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
keys[1].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
keys[2].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
keys[3].sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++){
switch(keys[i].jud){
case 0:{
if(keys[i].sta==0){
keys[i].jud=1;
}
break;
}
case 1:{
if(keys[i].sta==0){
if(last_key==i && keys[last_key].time<70){
keys[i].dou=1;
}
else{
keys[i].sign=1;
last_key=i;
}
keys[i].jud=2;
}
else
keys[i].jud=0;
break;
}
case 2:{
if(keys[i].sta==1)
keys[i].jud=0;
keys[i].time=0;
validity=1;
break;
}
}
}
if(validity && keys[last_key].time<200)
keys[last_key].time++;
}
}PWM:
输入捕获:
cubemx
PB4,PA15配置某定时器的通道
对应定时器里,内部时钟,直接输入捕获模式,预分频80-1,开启全局中断
keil
while前加
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);interrupt.c
uint ccr1,ccr2;
uint fre1,fre2;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM2){
ccr1=HAL_TIM_ReadCaptureValue(htim,TIM_CHANNEL_1);
__HAL_SetCounter(htim,0);//也可以用TIM2->CNT=0;
fre1=1000000/ccr1;
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
}
if(htim->Instance==TIM3){
ccr2=HAL_TIM_ReadCaptureValue(htim,TIM_CHANNEL_1);
__HAL_SetCounter(htim,0);//TIM3->CNT=0;
fre2=1000000/ccr2;
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
}
}输出:
cubemx
PWM Generation CH1,设置预分频值,自动重装载值,pulse,一般arr为100-1方便调duty
keil
while前加
HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);参数修改
__HAL_TIM_setCompare(&htim16,TIM_CHANNEL_1,daty_1);//占空比
__HAL_TIM_PRESCALER(&htim16,fre_n1);//一般这么改频率,fre_n1=800000/fre_ex1
__HAL_TIM_SetAutoreload(&htim16,fre_n2);//不推荐这么改,会同时影响频率和占空比ADC:
cubemx
PB12,15配置ADC_IN
keil
新建myadc.c和.h
myadc.h
#ifndef _MYADC_H_
#define _MYADC_H_
#include "main.h"
float get_ADC(ADC_HandleTypeDef *pin);
#endifmyadc.c
#include "myadc.h"
float get_ADC(ADC_HandleTypeDef *pin){
uint adc;
HAL_ADC_Start(pin);
adc=HAL_ADC_GetValue(pin);
return adc*3.3/4095.0;
}USART:
cubemx
PA9,PA10配置USART1异步模式,开启中断,修改波特率(一般9600)
keil
interrupt.c
#include "usart.h"
char redata[30];
uint redat;
uchar re_po;
void HAL_UART_Receive_IT(UART_HandleTypeDef *huart){
rxdata[rx_po++]=rx_dat;
HAL_UART_Receive_IT(&huart,rxdat,1);//一般用1,多字节接收需要disable overrun
}logic.c(功能集成)
#include "string.h"
void uart_proc(void){
if(rx_po!=0){
int temp=rx_po;
HAL_Delay(1);
if(temp==rx_po){
if(rx_po>0){
if(rx_po==22){
sscanf(rxdata,"%4s:%4s:%12s",va1,va2,va3);
}
else{
sprintf(text,"Error\r\n");
HAL_UART_Transmit(&huart,(uint8_t *)text,strlen(text),50);
}
rx_po=0;
memset(rxdata,0,30);
}
}
}
}I2C:
cubemx
PB6,7配置GPIO_Output
keil
copy过来i2c_hal.c和.h
在i2c_hal.c末尾新增
uchar eeprom_read(uchar addr){
uchar dat;
I2CStart();
I2CSendByte(0xa0);//器件地址+写位0
I2CWaitAck();
I2CSendByte(addr);//读取位置
I2CWaitAck();
I2CStop();//暂时结束
I2CStart();
I2CSendByte(0xa1);//器件地址+读位1
I2CWaitAck();
dat=I2CReceiveByte();
I2CSendAck();
I2CStop();
return dat;
}
uchar eeprom_write(uchar addr,uchar dat){
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}实际读写
//写入
uint fre1;//实际为16位,占两个字节
uchar fre_h=fre1>>8;
uchar fre_l=fre1&0xff;
eeprom_write(1,fre_h);
HAL_Delay(10);
eeprom_write(2,fre_l);
//读取
fre_r=eeprom_read(1)<<8+eeprom_read(2);
//如果是32位
eeprom_write(1, (value >> 24) & 0xFF);
eeprom_write(2, (value >> 16) & 0xFF);
eeprom_write(3, (value >> 8) & 0xFF);
eeprom_write(4, value & 0xFF);