笔者也是不得不要来做一做蓝桥了啊,希望到时候评测机器没有乱七八糟的毛病(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);
#endif

led.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);

#endif

interrupt.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);

#endif

myadc.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);