一题目展示

二代码解析 

1、头文件的相关定义与声明

#ifndef _code_h
#define _code_h

#include "stm32g4xx.h"                  // Device header
#include "stdio.h"
#include "string.h"
#include "stdint.h"

#include "lcd.h"
#include "main.h"
#include "gpio.h"
#include "tim.h"
#include "adc.h"
#include "usart.h"

void lcd_proc(void);
void key_proc(void);
void led_proc(u8 led_x,u8 led_mode);
void usart_proc(void);
double adc_proc(ADC_HandleTypeDef *hadc);

#endif

2、主函数的初始化

#include "code.h"
 
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	LCD_Init();
	LCD_SetTextColor(White);
	LCD_SetBackColor(Black);
	LCD_Clear(Black);
	
	HAL_TIM_Base_Start(&htim1);
	HAL_TIM_Base_Start(&htim2);
	HAL_TIM_Base_Start_IT(&htim3);
	
	HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_2);
    //Cubemx里将TIM15->PSC=8000-1,ARR=100-1,占空比30则设置为30-1
	TIM15->CCR2=30-1;
	HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
	
	HAL_ADC_Start(&hadc2);
  
	extern u8 my_pData;
	HAL_UART_Receive_IT(&huart1,&my_pData,1);

  while (1)
  {
		if(TIM1->CNT%100==0)
			lcd_proc();
		adc_proc(&hadc2);
		key_proc();
		usart_proc();
  }

3、各个模块的编写

#include "code.h"

double Capture_ccr;
/*---------------------------------------lcd-----------------------------------*/
u8 ui;
u16 N;
char lcd_val[21];
int NH=150;
void lcd_proc(void)
{
	led_proc(1,!ui);
	led_proc(2,ui);
	if(ui==0)
	{
		sprintf(lcd_val,"        DATA ");
		LCD_DisplayStringLine(Line1,(u8 *)lcd_val);
		sprintf(lcd_val,"       N:%dr/s ",N);
		LCD_DisplayStringLine(Line3,(u8 *)lcd_val);
		sprintf(lcd_val,"       D:%.0f%% ",Capture_ccr+1);
		LCD_DisplayStringLine(Line4,(u8 *)lcd_val);
		sprintf(lcd_val,"       U:%.1fV ",adc_proc(&hadc2));
		LCD_DisplayStringLine(Line5,(u8 *)lcd_val);
		sprintf(lcd_val,"                 P:%d",ui+1);
		LCD_DisplayStringLine(Line9,(u8 *)lcd_val);
	}
	else
	{
		sprintf(lcd_val,"        PARA ");
		LCD_DisplayStringLine(Line1,(u8 *)lcd_val);
		sprintf(lcd_val,"      NH:%d    ",NH);
		LCD_DisplayStringLine(Line3,(u8 *)lcd_val);
		sprintf(lcd_val,"                 P:%d",ui+1);
		LCD_DisplayStringLine(Line9,(u8 *)lcd_val);
	}
	
}

/*---------------------------------------key-----------------------------------*/

u8 key_old[4];
u8 key_val[4];
u8 key;

void key_proc(void)
{
	for(u8 i=0;i<4;i++)
	{
		key_val[i]=HAL_GPIO_ReadPin(i<3?GPIOB:GPIOA,GPIO_PIN_0<<i%3);
	}
	for(u8 i=0;i<4;i++)
	{
		if(key_val[i]==0&&key_old[i]==1)
		{
			HAL_Delay(20);
			if(key_val[i]==0&&key_old[i]==1)
			{
				key=i+1;
			}
		}
	}
	for(u8 i=0;i<4;i++)
	{
		key_old[i]=key_val[i];
	}
	switch(key)
	{
		case 1:
		{
			ui=!ui;
			LCD_Clear(Black);
			break;
		}
		case 2:
		{
			if(ui)NH+=50;
			if(NH>1000)NH=0;
			break;
		}
		case 3:
		{
			if(ui)NH-=50;
			if(NH<0)NH=1000;
			break;
		}
		case 4:
		{
			break;
		}
	}
	key=0;
}



/*---------------------------------------led-----------------------------------*/

void led_proc(u8 led_x,u8 led_mode)
{
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	if(led_mode)
	{
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led_x-1),GPIO_PIN_RESET);
	}
	else
	{
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led_x-1),GPIO_PIN_SET);
	}
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

/*---------------------------------------TIM-----------------------------------*/
u8 it_flag;
double Capture_tim[2];//涉及到小数计算,使用double类型,更加精确一些
u8 led_IT_mode;
//CCER寄存器的bit1可以用来控制输入捕获中断的触发方式
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM16)
	{
		if(it_flag==0)
		{
			TIM16->CNT=0;
			TIM16->CCER|=0x02;//在cubemx默认bite1为0,即上升沿触发,或为1则设置成下降沿触发
			it_flag=1;
		}
		else if(it_flag==1)
		{
			Capture_tim[0]=TIM16->CCR1;//记录下降沿此刻时间即为高电平持续时间
			TIM16->CCER&=0xFD;//改为上升沿触发
			it_flag=2;
		}
		else if(it_flag==2)
		{
			Capture_tim[1]=TIM16->CCR1;//此刻时间即为一个PWM波的周期
			Capture_ccr=100*Capture_tim[0]/Capture_tim[1];//占空比=高电平持续时间/PWM周期
			it_flag=0;
		}
	}
	
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	led_IT_mode=!led_IT_mode;
}

/*---------------------------------------adc-----------------------------------*/
double adc;
double K;
u8 tx_flag;
double adc_proc(ADC_HandleTypeDef *hadc)
{
	HAL_ADC_Start(hadc);
	adc=3.3*HAL_ADC_GetValue(hadc)/4095;
	
	if(Capture_ccr<=50)
	{
		K=-1/0.4*Capture_ccr/100+1.25;
	}
	else
	{
		K=1/0.4*Capture_ccr/100-5/4;
	}
	
	N=K*adc*1000/5;
	if(N>NH&&tx_flag==0)
	{	
		HAL_UART_Transmit(&huart1,(u8 *)"warn",sizeof("warn"),50);
		led_proc(3,1);
		tx_flag=1;
	}
	
	if(N<=NH)
	{	
		led_proc(3,led_IT_mode);
		tx_flag=0;
	}
	return adc;
}


/*---------------------------------------usart-----------------------------------*/

u8 my_pData;
char rx_val[21];
char tx_val[21];
u8 count;
u8 rx_flag;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	rx_val[count]=my_pData;
	count++;
	rx_flag=1;
	TIM2->CNT=0;
	HAL_UART_Receive_IT(&huart1,&my_pData,1);
}

void usart_proc(void)
{
	if(rx_flag==0)return;
	if(TIM2->CNT<50)return;
	if(strstr(rx_val,"?")!=NULL)
	{
		sprintf(tx_val,"%dr/s",N);
		HAL_UART_Transmit(&huart1,(u8 *)tx_val,strlen(tx_val),50);
	}
	else
	{
		HAL_UART_Transmit(&huart1,(u8 *)"error",strlen("error"),50);
	}
	rx_flag=0;
	count=0;
	memset(rx_val,NULL,sizeof(rx_val));
}

三结语

看过我之前的文章的小伙伴可能知道,在之前我串口是有问题,很高兴在今天终于解决了,问题发生在我之前一直以为lcd一行显示最多为20个字符,加上我使用sprintf来对其赋值,之前一直以为sprintf和strcpy不一样,是不会自动赋上结束符的,于是给lcd显示的数组就设置为20,但实际使用时发现当显示完整个数组,使用strlen测量这个数组时是发生了地址越界,所以才会导致串口判断出错,lcd显示数组最小应该也要为21。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐