多路ADC
在CubeMX里配置Number Of Conversion为通道数,给几个rank都配置自己的通道,把sampling time改成最大640.5 cycles
myadc.c
double v1,v2;
uint v1_value,v2_value;
void getADC(ADC_HandleTypeDef *hadc){
HAL_ADC_Start(hadc);
HAL_ADC_PollForConversion(hadc,50);//阻塞等待rank1转换完成才能继续
v1_value=HAL_ADC_GetValue(hadc);
v1=v1_value*3.3/4095.0;
HAL_ADC_PollForConversion(hadc,50);
v2_value=HAL_ADC_GetValue(hadc);
v2=v2_value*3.3/4095.0;
}ADC校准
在ADC初始化之后,第一次采样之前,只执行一次即可,可以解决采集到最大电压只有3.25的问题
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);ADC过采样
什么时候需要呢,一般开完校准大部分情况就够用了,如果12位精度满足不了,可以尝试一下过采样提升精度到16位
配置连续256次采样,右移4位取平均,得到的是最大4096*16的整数,只要在软件里/16就可以把有效位数提升至16位

然后采样时加一句等待转换完成
HAL_ADC_Start(&hadc2);
HAL_ADC_PollForConversion(&hadc2,10);//10表示等待时间,要大于转换时间
v=HAL_ADC_GetValue(&hadc2)*3.3/16.0/4065.0;
HAL_ADC_Stop(&hadc2);//也可以不加显示反转
需要时重新init
lcd.c
void REG_932X_Init_FB(void)
{
LCD_WriteReg(R227, 0x3008); // Set internal timing
LCD_WriteReg(R231, 0x0012); // Set internal timing
LCD_WriteReg(R239, 0x1231); // Set internal timing
LCD_WriteReg(R1, 0x0100); // 反转就是这个 //0x0100
....
LCD_WriteReg(R96, 0xA700); // 这个就是反转 0xA700
...
}
void LCD_Init_FB(void)
{
LCD_CtrlLinesConfig();
dummy = LCD_ReadReg(0);
if(dummy == 0x8230)
{
REG_8230_Init();
}
else
{
REG_932X_Init_FB();
}
dummy = LCD_ReadReg(0);
}串口
interrupt.c
char rxdata[20];
uint8_t rx_po,rxdat;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
rxdata[rx_po++]=rxdat;
HAL_UART_Receive_IT(huart,&rxdat,1);
}logic.c
extern uint8_t rx_po,rxdat;
extern char rxdata[];
if(rx_po!=0){
int temp=rx_po;
HAL_Delay(1);
if(temp==rx_po){
//解析代码
...
if(strncmp(rxdata,"PPP",3)==0){ //strncmp检查到字符串相等返回0,别忘了==0
sscanf(rxdata,"PPP%3d",rxnum);//匹配PPP后的三位数字
}
else{
sprintf(text,"error\r\n");
HAL_UART_Transmit(&huart1,(u8*)text,strlen(text),50)
}
rx_po=0;
memset(rxdata,0,20);
}
}RTC时钟
cubemx里找到RTC
直接Activate Clock Source和Activate Calendar,下面可以设置初始时间初始日期,Data Format设置二进制格式,根据需要开启内部闹钟和使能中断
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;//声明结构体
//需要调用时间时,从硬件获取时间
HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&sDate,RTC_FORMAT_BIN);
//需要更改时间时,也要把硬件的时间修改
sTime.Hours=h;
sTime.Minutes=m;
sTime.Seconds=s;
HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
sDate.Year=y;
sDate.Month=m;
sDate.Date=d;
HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)//如果需要闹钟中断
{
}占空比测量
在cubemx中再开启一个通道,选择间接测量,下面配置中此通道改为下降沿触发
void HAL_TIM_IC_RxCpltCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM3){
if(htim->CHANNEL==HAL_TIM_ACTIVE_CHANNEL_1){
ccr1a=HAL_TIM_ReadCaptureValue(htim,TIM_CHANNEL_1);
ccr1b=HAL_TIM_ReadCaptureValue(htim,TIM_CHANNEL_2);
duty1=ccr1b*100/ccr1a;
fre1=1000000/ccr1a;
TIM3->CNT=0;
HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_2);
}
}
}MCP4017读写
void mcp_write(u8 dat){
I2CStart();
I2CSendByte(0x5e);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
u8 mcp_read(void){
u8 dat;
I2CStart();
I2CSendByte(0x5f);
I2CWaitAck();
dat=I2CReceiveByte();
I2CSendNotAck();
return dat;
}按键双击
单击和长按那版的基础上改的
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM4){
keys[0].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN0);
keys[1].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN1);
keys[2].sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN2);
keys[3].sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN0);
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){
keys[i].jud=2;
keys[i].time=0;
}
else{
keys[i].jud=0;
}
break;
case 2:
if(keys[i].sta==1){
if(keys[i].time<200){
keys[i].sign=1; //如果严格区分单双击按键功能可以放到后面
keys[i].cnt++;
}
keys[i].jud=3;
}
else{
keys[i].time++;
if(keys[i].time>200){
keys[i].lon=1;
keys[i].cnt=0;
}
}
case 3:
keys[i].dtime++;
if(keys[i].dtime>200){ //结算时间0.2s过期不候
if(keys[i].cnt==2){
keys[i].dsign=1;
}
keys[i].dtime=0;
keys[i].cnt=0;
keys[i].jud=0;
}
else if(keys[i].sta==0){
keys[i].jud=1; //开启第二趟判断
}
break;
}
}
}
}