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闹钟的回调函数,在回调函数里进行对应的操作即可。
(可能不考,了解即可)