第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)

一.题目分析

(1).题目

(2).题目分析

1.按键功能分析

a. 按键1是功能切换按键,控制LED2闪烁的使能与失能,还要设置一个标志位记录这个状态,方便判断在LCD上显示ON还是OFF

b. 按键2是界面切换按键,两个界面来回跳转,由第二个界面跳转回第一个界面时,要保存设置的自动上报时间

c. 按键3是调整时间选择设置时/分/秒,同时被选中的对象高亮闪烁

d. 按键4是准确时间设置

二.CubeMX配置(结合原理图+手册讲解)

(1)基础配置

1.原理图分析

a.晶振配置-----24MHZ

2.实际操作

a.选择芯片型号(STM32G431RBT6)

b.配置系统 SYS

c.修改中断优先级的分组(抢占优先级4位+0位响应优先级)

d.配置时钟RCC

由上面原理图可知要将晶振配置成24MHZ采用HSE(高速外部时钟源)配合PLL(锁相环路)作为主时钟系统,这主要是为了充分利用芯片的高性能,PLLM是PLL时钟输入分频因子,配置PLLM使系统时钟达到80MHZ

(2)KEY+LED

1.原理图分析                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                

当按键不按下的时候PB1为高电平,按下去的时候就低电平,因此配置成浮空输入

2.实际操作

a.引脚设置

使用CubeMX设置好对应的GPIO端口,将PC8—PC15和PD2设置成输出PB1,PB0,PA0,PB2设置成输入

b.将PC8—PC15的LED的输出设置成High-----这样上电的时候灯是熄灭的

PD2是电源指示灯上电就应该点亮,所以输出默认为Low

(3)UART

1.原理图分析

2.实际操作

a.配置串口

b.使能串口

c.配置波特率

d.设置中断

(4)ADC

       1.原理图分析

ADC接入了两个滑变,分别是R37R38,PB15和PB12是ADC的通道,看下图知道PB15是ADC2的通道15,PB12是ADC1的通道11

两个ADC通常独立使用,互不影响

2.实际操作

a.配置引脚

b.配置ADC1

通道配置成单边输入

选择任意一个异步时钟

选择采样时间长一点

c.ADC2的配置和ADC1相同

(5)TIM

        1.原理图分析

分析历年真题,最常使用的PWM 引脚是PA6和PA7,因此下面操作配置这个两个引脚

2.实际操作

a.使能定时器6(基本定时器)

配置100ms进入一次中断

开启中断

b.配置定时器2(输入捕获)

PA15选择定时器2的通道1

选择复位模式

选择触发源T11FP1

系统时钟来自于内部时钟

通道1直接连接,通道2交叉连接

配置预分频和计数器周期

通道1上升沿通道2下降沿

定时器2和3捕获之后要进入到中断,因此打开中断

c.配置定时器3(输出PWM

定时器17的配置相同

配置PWM输出引脚

通道1

选择80分频,一兆的频率进行1000计数,频率就是1000HZ

使能自动重装载

TIM3的占空比设置成30%,则脉冲就设置成300

TIM17的占空比设置成60%,则脉冲设置成600

TIM3

TIM17

d.配置定时器15(输出方波---是比较输出模式)

配置方波输出引脚

选择内部时钟作为计数单元

选择输出比较模式

选择80分频

使能自动重装载

输出比较模式设置成翻转

使能中断

(6)RTC

    1.原理图分析

     2.实际操作

a.使能日历和时钟源

b.选择外部时钟

外部时钟经过32分频之后是750KHz

RTC时钟频率 = RTC时钟源 / ((Asynchronous Predivider value + 1) * (Synchronous Predivider value + 1))

因此,将Asynchronous Predivider Value设置为125,Synchronous Predivider value 设置为6000,这样,RTC时钟频率就为1Hz

c.设置日历起始时间(二进制)

(7).最终生成程序

当出现以下错误时

可从考试给的资源数据包里

复制以下文件到此程序的MDK_ARM

三.相关代码实现

代码将分为以下三层详细讲解

(1)MAIN

1.包含路径

#include "main.h"
#include "RCC\bsp_rcc.h"
#include "KEY_LED\bsp_key_led.h"
#include "LCD\bsp_lcd.h"
#include "UART\bsp_uart.h"
#include "I2C\bsp_i2c.h"
#include "ADC\bsp_adc.h"
#include "RTC\bsp_rtc.h"

2全局变量声明

//*减速变量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度
__IO uint32_t uwTick_Usart_Set_Point = 0;//控制Usart_Proc的执行速度

//*按键扫描专用变量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;

//*LED专用变量
uint8_t ucLed;

//*LCD显示专用变量
uint8_t Lcd_Disp_String[21];//最多显示20个字符

//*串口专用变量
uint16_t counter = 0;
uint8_t str[40];
uint8_t rx_buffer;
uint8_t rx_buf[100];//接收到的指令临时存放缓冲区
uint8_t rx_buf_index = 0;//控制数据往buf里边存储的顺序

//用户自定义变量区
uint8_t Interface_Num;//0x00-显示界面,0x10-设置上报时间的小时,0x11-设置分钟,0x12-设置秒。
float R37_Voltage;
uint8_t k_int = 1;
uint8_t LED_Ctrl = 0;// 0-打开,1关闭,控制LED报警功能
uint8_t Clock_Comp_Disp[3] = {0,0,0};//闹钟比较值的初值(显示专用)
uint8_t Clock_Comp_Ctrl[3] = {0,0,0};//闹钟比较值的初值(控制专用)
__IO uint32_t uwTick_SETTING_TIME_Set_Point = 0;//控制待设置的时间数值闪烁
uint8_t SETTING_TIME_Ctrl = 0;// 0-亮,1-灭,控制时间设置界面的待设置值的闪烁功能
uint8_t Ctrl_Uart_Send_Time_Data_Times = 0;// 控制只允许到闹钟时间后只上报一次
__IO uint32_t Uart_Rev_Data_Delay_Time = 0;//控制串口接收数据的等待时间
_Bool Start_Flag;//起始位判断
__IO uint32_t uwTick_LED_bulingbuling_Set_Point = 0;//控制LED报警闪烁的打点变量

3.子函数声明

void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);

4.系统主函数

int main(void)
{
  HAL_Init();
  SystemClock_Config();
/*bsp资源的初始化*/
  KEY_LED_Init();	
  LCD_Init();
  LCD_Clear(White);
  LCD_SetBackColor(White);
  LCD_SetTextColor(Blue);		
  UART1_Init();
  I2CInit();
  ADC2_Init();
  RTC_Init();
  
  //*EEPROM测试
  iic_24c02_read(&k_int,0,1);//去EEPOM中读取k的初值	
  //*串口接收中断打开
  HAL_UART_Receive_IT(&huart1, (uint8_t *)(&rx_buffer), 1);	
  while (1)
  {
		Key_Proc();
		Led_Proc();
		Lcd_Proc();
		Usart_Proc();		
  }
}

5.按键扫描子函数

a.逻辑分析

B1完成LED报警功能的打开和关闭

B2完成两个界面的切换

默认设置显示页面的标志位是0x00按下按键切换成0x10设置页面的标志位)

B3切换时分秒

只有当高位等于1时才能切换(即页面停留在setting时),每按下一次标志位就加1 ,当标志位变成0x12时,就强制变回0x10,以达到轮转功能

B4调整设定值的时分秒

B3已经设置了时/分/秒,使用B4修改时分秒,到达24时/60分/60秒就置零

b.程序源码
void Key_Proc(void)
{
	if((uwTick -  uwTick_Key_Set_Point)<50)	return;//减速函数
		uwTick_Key_Set_Point = uwTick;

	ucKey_Val = Key_Scan();
	unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val); 
	ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);	
	ucKey_Old = ucKey_Val;	
	if(unKey_Down == 1)//B1完成LED报警功能的打开和关闭
	{
		LED_Ctrl ^= 0x01;//让最后一位翻滚
	}
	
	if(unKey_Down == 2)//B2完成两个界面的切换
	{
		if(Interface_Num == 0x00)
		{
			LCD_Clear(White);//清屏
			Interface_Num = 0x10;			
		}
		else if((Interface_Num>>4) == 0x1)
		{
			LCD_Clear(White);//清屏
			Interface_Num = 0x00;	

			Clock_Comp_Ctrl[0] = Clock_Comp_Disp[0];	//更新闹钟显示值到控制值
			Clock_Comp_Ctrl[1] = Clock_Comp_Disp[1];	//更新闹钟显示值到控制值	
			Clock_Comp_Ctrl[2] = Clock_Comp_Disp[2];	//更新闹钟显示值到控制值				
		}			
	}
	if(unKey_Down == 3)//B3切换时分秒
	{
	 if((Interface_Num>>4) == 0x1)
			if(++Interface_Num == 0x13)
					Interface_Num = 0x10;
	}	
	if(unKey_Down == 4)//B4调整设定值的时分秒
	{
		if(Interface_Num == 0x10)
		{
			if( ++Clock_Comp_Disp[0] == 24)
				Clock_Comp_Disp[0] = 0;
		}
		else if(Interface_Num == 0x11)
		{
			if( ++Clock_Comp_Disp[1] == 60)
				Clock_Comp_Disp[1] = 0;		
		}
		else if(Interface_Num == 0x12)
		{
			if( ++Clock_Comp_Disp[2] == 60)
				Clock_Comp_Disp[2] = 0;			
		}
	}		
}

6.LED扫描子函数

a.逻辑分析

该板子是低电平点亮,8个led灯使用的是高8位所以需要左移8位,led等于几就是将高8位中第几位设置成低电平即点亮,由于led与lcd复用引脚最后打开锁存器让值被写入之后,立刻关闭锁存器防止影响lcd

b.程序源码
void Led_Proc(void)
{
	if((uwTick -  uwTick_Led_Set_Point)<50)	return;//减速函数
		uwTick_Led_Set_Point = uwTick;
	if(LED_Ctrl == 0x1)//关闭LED的功能的时候
		ucLed = 0x00;
	else//开启LED功能的时候
	{
		if(R37_Voltage>=(3.3*k_int*0.1))
		{
			if((uwTick-uwTick_LED_bulingbuling_Set_Point)>=200)
			{
				uwTick_LED_bulingbuling_Set_Point = uwTick;
				ucLed ^= 0x1;
			}
		}
		else
			ucLed = 0x00;			
	}
	LED_Disp(ucLed);
}

7.LCD扫描子函数

a.逻辑分析

分为数据采集区和数据显示区和时间设置区三部分

1.数据采集区使用HAL_RTC_GetTimeHAL_RTC_GetDate读取日期和时间

a. HAL_RTC_SetTime

函数原型HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);

hrtc:指向RTC_HandleTypeDef结构体的指针,该结构体包含了RTC模块的配置信息

sTime:指向RTC_TimeTypeDef结构体的指针,该结构体用于存储时间信息

Format:这个参数指定了时间数据的格式,可以是RTC_FORMAT_BIN(二进制格式) 或RTC_FORMAT_BCD(BCD格式)

b. HAL_RTC_SetDate

函数原型HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);

hrtc:指向RTC_HandleTypeDef结构体的指针,该结构体包含了RTC模块的配置信息

· sDate:指向RTC_DateTypeDef结构体的指针,该结构体用于存储日期信息

Format:这个参数指定了日期数据的格式,可以是RTC_FORMAT_BIN(二进制格 式)或 RTC_FORMAT_BCD(BCD格式)

2.数据显示区使用sprintfLCD_DisplayStringLine在LCD上相应的位置显示内容

a. sprintf

函数原型int sprintf(char *str, const char *format, ...);

str :一个字符数组的指针,用于存储生成的字符串

format :格式化字符串,用于指定要输出的内容和格式

后面的省略号:可变参数列表,用于提供与格式化字符串中的占位符相对应的值

b.LCD_DisplayStringLine

函数原型void LCD_DisplayStringLine(u8 Line, u8 *ptr)

Line:显示的位置

ptr:指向显示内容

3.时间设置区定义SETTING_TIME_Ctrl初始值为00标志亮,1标志灭,控制时间设置界面的待设置值的闪烁功能,设置延时时间,时间到达状态翻滚,以此达到闪烁功能

b.程序源码
void Lcd_Proc(void)
{
	if((uwTick -  uwTick_Lcd_Set_Point)<100)	return;//减速函数
		uwTick_Lcd_Set_Point = uwTick;

		//数据采集区
		R37_Voltage = ((((float)getADC2())/4096)*3.3);
		HAL_RTC_GetTime(&hrtc, &H_M_S_Time, RTC_FORMAT_BIN);//读取日期和时间必须同时使用
		HAL_RTC_GetDate(&hrtc, &Y_M_D_Date, RTC_FORMAT_BIN);

		//数据显示区
		if(Interface_Num == 0x00)//内容显示界面
		{
			sprintf((char *)Lcd_Disp_String, " V1:%4.2fV",R37_Voltage);
			LCD_DisplayStringLine(Line2, Lcd_Disp_String);	
			
			sprintf((char *)Lcd_Disp_String, "  k:%3.1f",(k_int*0.1));
			LCD_DisplayStringLine(Line4, Lcd_Disp_String);	
			
			if(LED_Ctrl == 0)
				sprintf((char *)Lcd_Disp_String, "    LED:ON ");		
			else
				sprintf((char *)Lcd_Disp_String, "    LED:OFF");						
		  LCD_DisplayStringLine(Line6, Lcd_Disp_String);	
		
			sprintf((char *)Lcd_Disp_String, "    T:%02d-%02d-%02d",(unsigned int)H_M_S_Time.Hours,(unsigned int)H_M_S_Time.Minutes,(unsigned int)H_M_S_Time.Seconds);
			LCD_DisplayStringLine(Line8, Lcd_Disp_String);			
		}
		
		//时间设置区
		if((Interface_Num>>4) == 0x1)//进入设置界面
		{		
			sprintf((char *)Lcd_Disp_String, "       Setting");
			LCD_DisplayStringLine(Line2, Lcd_Disp_String);					
			sprintf((char *)Lcd_Disp_String, "      %02d-%02d-%02d",(unsigned int)Clock_Comp_Disp[0],(unsigned int)Clock_Comp_Disp[1],(unsigned int)Clock_Comp_Disp[2]);
			if((uwTick - uwTick_SETTING_TIME_Set_Point)>=500)
			{
				uwTick_SETTING_TIME_Set_Point = uwTick;
				SETTING_TIME_Ctrl ^= 0x1;
			}
			
			if(SETTING_TIME_Ctrl == 0x1)//用来控制闪烁,时间设置时候的闪烁。
			{
				if(Interface_Num == 0x10)//设置时	
					{
						Lcd_Disp_String[6] = ' ';
						Lcd_Disp_String[7] = ' ';						
					}
				else if(Interface_Num == 0x11)//设置分
				{
						Lcd_Disp_String[9] = ' ';
						Lcd_Disp_String[10] = ' ';					
				}
				else if(Interface_Num == 0x12)//设置秒
				{
						Lcd_Disp_String[12] = ' ';
						Lcd_Disp_String[13] = ' ';					
				}
			}
			LCD_DisplayStringLine(Line5, Lcd_Disp_String);		

			
		}
}

8.串口扫描子函数

a.逻辑分析

1.定时上报电压

判断时间是否达到定时时间,达到就上报时间,定义变量uint8_tCtrl_Uart_Send_Time_Data_Times = 0控制只上报一次,上报电压值+K+时间

使用HAL_UART_Transmit,向指定串口发送数据

HAL_UART_Transmit函数原型

参数含义

2.以“k0.1\n”的形式向设备发送命令,设备接收到命令执行后,回复ok\n

数据发送是一个字节一个字节的发送,当第一个数据k发送出去时,开始启动计时,给定一个接收数据的时间,在此时间内,接收到的所有数据都会放入环形缓冲区rx_buf[ ],还需要一段时间去处理环形缓冲区内接收到的数据,判断是否符合题目要求的格式,不符合就不处理,符合就回应ok,并使用iic_24c02_write将k的数值写到k_int,同时还需要iic_24c02_read在单片机上电的时候去EEPROM中读出k的初值

b.程序源码
void Usart_Proc(void)
{
	if((uwTick -  uwTick_Usart_Set_Point)<30)	return;//减速函数
	uwTick_Usart_Set_Point = uwTick;	
	//闹钟时间到
	if((H_M_S_Time.Hours == Clock_Comp_Ctrl[0])&&(H_M_S_Time.Minutes == Clock_Comp_Ctrl[1])&&(H_M_S_Time.Seconds == Clock_Comp_Ctrl[2]))
	{
		if(Ctrl_Uart_Send_Time_Data_Times == 0)//控制只发送一次数据,虽然通过扫描进来了五次
		{
				Ctrl_Uart_Send_Time_Data_Times = 1;
				sprintf(str, "%4.2f+%3.1f+%02d%02d%02d\n", R37_Voltage,(k_int*0.1),(unsigned int)H_M_S_Time.Hours,(unsigned int)H_M_S_Time.Minutes,(unsigned int)H_M_S_Time.Seconds);
				HAL_UART_Transmit(&huart1,(unsigned char *)str, strlen(str), 50);			
		}
	}
	else 
		Ctrl_Uart_Send_Time_Data_Times = 0;	//当时间变化或者控制值变化,两者不等的时候,恢复下一次数据发送允许。

	//串口接收的数据处理
		if(((uwTick - Uart_Rev_Data_Delay_Time)<=300)&&(uwTick - Uart_Rev_Data_Delay_Time)>=200)//200ms~300ms之内处理数据
	{
		if(rx_buf_index==6)//接收到了6个数据
		{
			if((rx_buf[0] == 0x6B)&&(rx_buf[1] == 0x30)&&(rx_buf[2] == 0x2E)&&(rx_buf[4] == 0x5C)&&(rx_buf[5] == 0x6E))
			{
				if((rx_buf[3]>=0x31)&&(rx_buf[3]<=0x39))
				{
					k_int = rx_buf[3] - 0x30; 
					sprintf(str, "OK\n");
					HAL_UART_Transmit(&huart1,(unsigned char *)str, strlen(str), 50);		
					iic_24c02_write(&k_int, 0, 1);					
				}
			}			
		}
	  rx_buf_index = 0;	
		Start_Flag = 0;		   
	}
}

9.串口接收中断回调函数

a.逻辑分析

使用rx_buffer保存接收到的数据,rx_buf_index索引缓冲区,当接收到的第一个数据是0x6B(k的十六进制),记录此时的时间,定义好标志位表示第一个数据的到来,同时只要符合此标记位Start_Flag == 1,就让让索引缓冲值+1,最后串口发送的所有数据都会被接收到缓冲区

b.程序源码

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

	if((rx_buffer == 0x6B)&&(rx_buf_index == 0))
	{
		Uart_Rev_Data_Delay_Time = uwTick;//接收到第一个数据启动计时		
		Start_Flag = 1;
	}
	if(Start_Flag == 1)
	{		
		rx_buf[rx_buf_index] = rx_buffer;
		rx_buf_index++;		
	}	
	HAL_UART_Receive_IT(&huart1, (uint8_t *)(&rx_buffer), 1);	
}

(2).BSP

1.LCD模块

以下代码比赛时直接从比赛给的资料里面移植

bsp_lcd.c
#include "LCD\bsp_lcd.h"
#include "LCD\bsp_fonts.h"
//#include "systick.h"
static  vu16 TextColor = 0x0000, BackColor = 0xFFFF;
vu16 dummy;
void Delay_LCD(u16 n)
{
	u16 i,j;
	for (i = 0;i<n;++i)
		for(j=0;j<3000;++j);
}

/*
	uC8230型液晶控制器寄存器配置
*/
void REG_8230_Init(void)
{
	LCD_WriteReg(0x0000,0x0001);
	Delay_LCD(1000); 
	LCD_WriteReg(0x0001,0x0000);
	LCD_WriteReg(0x0010,0x1790);
	LCD_WriteReg(0x0060,0x2700);
	LCD_WriteReg(0x0061,0x0001);
	LCD_WriteReg(0x0046,0x0002);
	LCD_WriteReg(0x0013,0x8010);
	LCD_WriteReg(0x0012,0x80fe);
	LCD_WriteReg(0x0002,0x0500);
	LCD_WriteReg(0x0003,0x1030);
	
	LCD_WriteReg(0x0030,0x0303);
	LCD_WriteReg(0x0031,0x0303);
	LCD_WriteReg(0x0032,0x0303);
	LCD_WriteReg(0x0033,0x0300);
	LCD_WriteReg(0x0034,0x0003);
	LCD_WriteReg(0x0035,0x0303);
	LCD_WriteReg(0x0036,0x0014);
	LCD_WriteReg(0x0037,0x0303);
	LCD_WriteReg(0x0038,0x0303);
	LCD_WriteReg(0x0039,0x0303);
	LCD_WriteReg(0x003a,0x0300);
	LCD_WriteReg(0x003b,0x0003);
	LCD_WriteReg(0x003c,0x0303);
	LCD_WriteReg(0x003d,0x1400);
	  
	LCD_WriteReg(0x0092,0x0200);
	LCD_WriteReg(0x0093,0x0303);
	LCD_WriteReg(0x0090,0x080d); 
	LCD_WriteReg(0x0003,0x1018); 
	LCD_WriteReg(0x0007,0x0173);
}

void REG_932X_Init(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  , 0x0000); // set SS and SM bit		  //0x0100
	LCD_WriteReg(R2  , 0x0700); // set 1 line inversion
	LCD_WriteReg(R3  , 0x1030);   // set GRAM write direction and BGR=1.
	LCD_WriteReg(R4  , 0x0000);   // Resize register
	LCD_WriteReg(R8  , 0x0207);   // set the back porch and front porch
	LCD_WriteReg(R9  , 0x0000);   // set non-display area refresh cycle ISC[3:0]
	LCD_WriteReg(R10 , 0x0000);   // FMARK function
	LCD_WriteReg(R12 , 0x0000); // RGB interface setting
	LCD_WriteReg(R13 , 0x0000);   // Frame marker Position
	LCD_WriteReg(R15 , 0x0000); // RGB interface polarity
	/**************Power On sequence ****************/
	LCD_WriteReg(R16 , 0x0000);   // SAP, BT[3:0], AP, DSTB, SLP, STB
	LCD_WriteReg(R17 , 0x0007);   // DC1[2:0], DC0[2:0], VC[2:0]
	LCD_WriteReg(R18 , 0x0000); // VREG1OUT voltage
	LCD_WriteReg(R19 , 0x0000);   // VDV[4:0] for VCOM amplitude
//	Delay_Ms(200);                    // Delay 200 MS , Dis-charge capacitor power voltage
	HAL_Delay(200);
	LCD_WriteReg(R16 , 0x1690);   // SAP, BT[3:0], AP, DSTB, SLP, STB
	LCD_WriteReg(R17 , 0x0227); // R11H=0x0221 at VCI=3.3V, DC1[2:0], DC0[2:0], VC[2:0]
//	Delay_Ms(50);      // Delay 50ms
	HAL_Delay(50);
	LCD_WriteReg(R18 , 0x001D); // External reference voltage= Vci;
//	Delay_Ms(50);      // Delay 50ms
	HAL_Delay(50);
	LCD_WriteReg(R19 , 0x0800); // R13H=1D00 when R12H=009D;VDV[4:0] for VCOM amplitude
	LCD_WriteReg(R41 , 0x0014); // R29H=0013 when R12H=009D;VCM[5:0] for VCOMH
	LCD_WriteReg(R43 , 0x000B);   // Frame Rate = 96Hz
//	Delay_Ms(50);      // Delay 50ms
	HAL_Delay(50);
	LCD_WriteReg(R32 , 0x0000); // GRAM horizontal Address
	LCD_WriteReg(R33 , 0x0000); // GRAM Vertical Address
	/* ----------- Adjust the Gamma Curve ---------- */
	LCD_WriteReg(R48 , 0x0007);
	LCD_WriteReg(R49 , 0x0707);
	LCD_WriteReg(R50 , 0x0006);
	LCD_WriteReg(R53 , 0x0704);
	LCD_WriteReg(R54 , 0x1F04);
	LCD_WriteReg(R55 , 0x0004);
	LCD_WriteReg(R56 , 0x0000);
	LCD_WriteReg(R57 , 0x0706);
	LCD_WriteReg(R60 , 0x0701);
	LCD_WriteReg(R61 , 0x000F);
	/* ------------------ Set GRAM area --------------- */
	LCD_WriteReg(R80 , 0x0000);   // Horizontal GRAM Start Address
	LCD_WriteReg(R81 , 0x00EF);   // Horizontal GRAM End Address
	LCD_WriteReg(R82 , 0x0000); // Vertical GRAM Start Address
	LCD_WriteReg(R83 , 0x013F); // Vertical GRAM Start Address
	LCD_WriteReg(R96 , 0x2700); // Gate Scan Line		  0xA700
	LCD_WriteReg(R97 , 0x0001); // NDL,VLE, REV
	LCD_WriteReg(R106, 0x0000); // set scrolling line
	/* -------------- Partial Display Control --------- */
	LCD_WriteReg(R128, 0x0000);   
	LCD_WriteReg(R129, 0x0000);
	LCD_WriteReg(R130, 0x0000);
	LCD_WriteReg(R131, 0x0000);
	LCD_WriteReg(R132, 0x0000);
	LCD_WriteReg(R133, 0x0000);
	/* -------------- Panel Control ------------------- */
	LCD_WriteReg(R144, 0x0010);
	LCD_WriteReg(R146, 0x0000);
	LCD_WriteReg(R147, 0x0003);
	LCD_WriteReg(R149, 0x0110);
	LCD_WriteReg(R151, 0x0000);
	LCD_WriteReg(R152, 0x0000);
	   /* Set GRAM write direction and BGR = 1 */
	   /* I/D=01 (Horizontal : increment, Vertical : decrement) */
	   /* AM=1 (address is updated in vertical writing direction) */
	LCD_WriteReg(R3  , 0x01018);  //0x1018
	
	LCD_WriteReg(R7  , 0x0173); // 262K color and display ON
}
/*******************************************************************************
* Function Name  : STM3210B_LCD_Init
* Description    : Initializes the LCD.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_Init(void)
{ 
	LCD_CtrlLinesConfig();
	dummy = LCD_ReadReg(0);	
	
	if(dummy == 0x8230){
		REG_8230_Init();
	}
	else{
		REG_932X_Init();	
	}
	dummy = LCD_ReadReg(0);	

}
/*******************************************************************************
* Function Name  : LCD_SetTextColor
* Description    : Sets the Text color.
* Input          : - Color: specifies the Text color code RGB(5-6-5).
* Output         : - TextColor: Text color global variable used by LCD_DrawChar
*                  and LCD_DrawPicture functions.
* Return         : None
*******************************************************************************/
void LCD_SetTextColor(vu16 Color)
{
	TextColor = Color;
}
/*******************************************************************************
* Function Name  : LCD_SetBackColor
* Description    : Sets the Background color.
* Input          : - Color: specifies the Background color code RGB(5-6-5).
* Output         : - BackColor: Background color global variable used by 
*                  LCD_DrawChar and LCD_DrawPicture functions.
* Return         : None
*******************************************************************************/
void LCD_SetBackColor(vu16 Color)
{
	BackColor = Color;
}
/*******************************************************************************
* Function Name  : LCD_ClearLine
* Description    : Clears the selected line.
* Input          : - Line: the Line to be cleared.
*                    This parameter can be one of the following values:
*                       - Linex: where x can be 0..9
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_ClearLine(u8 Line)
{
	LCD_DisplayStringLine(Line, "                    ");
}
/*******************************************************************************
* Function Name  : LCD_Clear
* Description    : Clears the hole LCD.
* Input          : Color: the color of the background.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_Clear(u16 Color)
{
	u32 index = 0;
	LCD_SetCursor(0x00, 0x0000); 
	LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	for(index = 0; index < 76800; index++)
	{
		LCD_WriteRAM(Color);    
	}
}
/*******************************************************************************
* Function Name  : LCD_SetCursor
* Description    : Sets the cursor position.
* Input          : - Xpos: specifies the X position.
*                  - Ypos: specifies the Y position. 
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_SetCursor(u8 Xpos, u16 Ypos)
{ 
	LCD_WriteReg(R32, Xpos);
	LCD_WriteReg(R33, Ypos);
}
/*******************************************************************************
* Function Name  : LCD_DrawChar
* Description    : Draws a character on LCD.
* Input          : - Xpos: the Line where to display the character shape.
*                    This parameter can be one of the following values:
*                       - Linex: where x can be 0..9
*                  - Ypos: start column address.
*                  - c: pointer to the character data.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_DrawChar(u8 Xpos, u16 Ypos, uc16 *c)
{
	u32 index = 0, i = 0;
	u8 Xaddress = 0;
   
	Xaddress = Xpos;
	LCD_SetCursor(Xaddress, Ypos);
  
	for(index = 0; index < 24; index++)
	{
		LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
		for(i = 0; i < 16; i++)
		{
			if((c[index] & (1 << i)) == 0x00)
			{
				LCD_WriteRAM(BackColor);
			}
			else
			{
				LCD_WriteRAM(TextColor);
			}
		}
		Xaddress++;
		LCD_SetCursor(Xaddress, Ypos);
	}
}
/*******************************************************************************
* Function Name  : LCD_DisplayChar
* Description    : Displays one character (16dots width, 24dots height).
* Input          : - Line: the Line where to display the character shape .
*                    This parameter can be one of the following values:
*                       - Linex: where x can be 0..9
*                  - Column: start column address.
*                  - Ascii: character ascii code, must be between 0x20 and 0x7E.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_DisplayChar(u8 Line, u16 Column, u8 Ascii)
{
	Ascii -= 32;
	LCD_DrawChar(Line, Column, &ASCII_Table[Ascii * 24]);
}
/*******************************************************************************
* Function Name  : LCD_DisplayStringLine
* Description    : Displays a maximum of 20 char on the LCD.
* Input          : - Line: the Line where to display the character shape .
*                    This parameter can be one of the following values:
*                       - Linex: where x can be 0..9
*                  - *ptr: pointer to string to display on LCD.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_DisplayStringLine(u8 Line, u8 *ptr)
{
	u32 i = 0;
	u16 refcolumn = 319;//319;

	while ((*ptr != 0) && (i < 20))	 //	20
	{
		LCD_DisplayChar(Line, refcolumn, *ptr);
		refcolumn -= 16;
		ptr++;
		i++;
	}
}
/*******************************************************************************
* Function Name  : LCD_SetDisplayWindow
* Description    : Sets a display window
* Input          : - Xpos: specifies the X buttom left position.
*                  - Ypos: specifies the Y buttom left position.
*                  - Height: display window height.
*                  - Width: display window width.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_SetDisplayWindow(u8 Xpos, u16 Ypos, u8 Height, u16 Width)
{
	if(Xpos >= Height)
	{
		LCD_WriteReg(R80, (Xpos - Height + 1));
	}
	else
	{
		LCD_WriteReg(R80, 0);
	}
	LCD_WriteReg(R81, Xpos);
	if(Ypos >= Width)
	{
		LCD_WriteReg(R82, (Ypos - Width + 1));
	}  
	else
	{
		LCD_WriteReg(R82, 0);
	}
	/* Vertical GRAM End Address */
	LCD_WriteReg(R83, Ypos);
	LCD_SetCursor(Xpos, Ypos);
}
/*******************************************************************************
* Function Name  : LCD_WindowModeDisable
* Description    : Disables LCD Window mode.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_WindowModeDisable(void)
{
	LCD_SetDisplayWindow(239, 0x13F, 240, 320);
	LCD_WriteReg(R3, 0x1018);    
}
/*******************************************************************************
* Function Name  : LCD_DrawLine
* Description    : Displays a line.
* Input          : - Xpos: specifies the X position.
*                  - Ypos: specifies the Y position.
*                  - Length: line length.
*                  - Direction: line direction.
*                    This parameter can be one of the following values: Vertical 
*                    or Horizontal.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_DrawLine(u8 Xpos, u16 Ypos, u16 Length, u8 Direction)
{
	u32 i = 0;
  
	LCD_SetCursor(Xpos, Ypos);
	if(Direction == Horizontal)
	{
		LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
		for(i = 0; i < Length; i++)
		{
			LCD_WriteRAM(TextColor);
		}
	}
	else
	{
		for(i = 0; i < Length; i++)
		{
			LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
			LCD_WriteRAM(TextColor);
			Xpos++;
			LCD_SetCursor(Xpos, Ypos);
		}
	}
}
/*******************************************************************************
* Function Name  : LCD_DrawRect
* Description    : Displays a rectangle.
* Input          : - Xpos: specifies the X position.
*                  - Ypos: specifies the Y position.
*                  - Height: display rectangle height.
*                  - Width: display rectangle width.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_DrawRect(u8 Xpos, u16 Ypos, u8 Height, u16 Width)
{
	LCD_DrawLine(Xpos, Ypos, Width, Horizontal);
	LCD_DrawLine((Xpos + Height), Ypos, Width, Horizontal);
  
	LCD_DrawLine(Xpos, Ypos, Height, Vertical);
	LCD_DrawLine(Xpos, (Ypos - Width + 1), Height, Vertical);
}
/*******************************************************************************
* Function Name  : LCD_DrawCircle
* Description    : Displays a circle.
* Input          : - Xpos: specifies the X position.
*                  - Ypos: specifies the Y position.
*                  - Height: display rectangle height.
*                  - Width: display rectangle width.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_DrawCircle(u8 Xpos, u16 Ypos, u16 Radius)
{
	s32  D;
	u32  CurX;
	u32  CurY;
  
  	D = 3 - (Radius << 1);
  	CurX = 0;
  	CurY = Radius;
  
  	while (CurX <= CurY)
  	{
	    LCD_SetCursor(Xpos + CurX, Ypos + CurY);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);
	
	    LCD_SetCursor(Xpos + CurX, Ypos - CurY);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);
	
	    LCD_SetCursor(Xpos - CurX, Ypos + CurY);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);
	
	    LCD_SetCursor(Xpos - CurX, Ypos - CurY);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);
	
	    LCD_SetCursor(Xpos + CurY, Ypos + CurX);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);
	
	    LCD_SetCursor(Xpos + CurY, Ypos - CurX);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);
	
	    LCD_SetCursor(Xpos - CurY, Ypos + CurX);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);
	
	    LCD_SetCursor(Xpos - CurY, Ypos - CurX);
	    LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	    LCD_WriteRAM(TextColor);

	    if (D < 0)
	    { 
	      D += (CurX << 2) + 6;
	    }
	    else
	    {
	      D += ((CurX - CurY) << 2) + 10;
	      CurY--;
	    }
	    CurX++;
  	}
}
/*******************************************************************************
* Function Name  : LCD_DrawMonoPict
* Description    : Displays a monocolor picture.
* Input          : - Pict: pointer to the picture array.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_DrawMonoPict(uc32 *Pict)
{
	u32 index = 0, i = 0;

	LCD_SetCursor(0, 319); 

	LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
	for(index = 0; index < 2400; index++)
	{
		for(i = 0; i < 32; i++)
		{
			if((Pict[index] & (1 << i)) == 0x00)
			{
				LCD_WriteRAM(BackColor);
			}
			else
			{
				LCD_WriteRAM(TextColor);
			}
		}
	}
}
/*******************************************************************************
* Function Name  : LCD_WriteBMP
* Description    : Displays a bitmap picture loaded in the internal Flash.
* Input          : - BmpAddress: Bmp picture address in the internal Flash.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_WriteBMP(u32 BmpAddress)
{
	u32 index = 0, size = 0;

	size = *(vu16 *) (BmpAddress + 2);
	size |= (*(vu16 *) (BmpAddress + 4)) << 16;

	index = *(vu16 *) (BmpAddress + 10);
	index |= (*(vu16 *) (BmpAddress + 12)) << 16;
	size = (size - index)/2;
	BmpAddress += index;

	LCD_WriteReg(R3, 0x1008);
	LCD_WriteRAM_Prepare();
	for(index = 0; index < size; index++)
	{
		LCD_WriteRAM(*(vu16 *)BmpAddress);
		BmpAddress += 2;
	}
	LCD_WriteReg(R3, 0x1018);
}
/*******************************************************************************
* Function Name  : LCD_WriteReg
* Description    : Writes to the selected LCD register.
* Input          : - LCD_Reg: address of the selected register.
*                  - LCD_RegValue: value to write to the selected register.
* Output         : None
* Return         : None
*******************************************************************************/
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
	GPIOB->BRR  |= GPIO_PIN_9;  	
	GPIOB->BRR  |= GPIO_PIN_8;  	
	GPIOB->BSRR |= GPIO_PIN_5; 	
	
	GPIOC->ODR = LCD_Reg; 
	GPIOB->BRR  |= GPIO_PIN_5; 
	__nop();
	__nop();
	__nop();	
	GPIOB->BSRR |= GPIO_PIN_5; 
	GPIOB->BSRR |= GPIO_PIN_8; 

	GPIOC->ODR = LCD_RegValue; 
	GPIOB->BRR  |= GPIO_PIN_5; 
	__nop();
	__nop();
	__nop();  
	GPIOB->BSRR |= GPIO_PIN_5; 
	GPIOB->BSRR |= GPIO_PIN_8; 
}
/*******************************************************************************
* Function Name  : LCD_ReadReg
* Description    : Reads the selected LCD Register.
* Input          : None
* Output         : None
* Return         : LCD Register Value.
*******************************************************************************/
u16 LCD_ReadReg(u8 LCD_Reg)
{
	u16 temp;

	GPIOB->BRR |= GPIO_PIN_9;  
	GPIOB->BRR |= GPIO_PIN_8;  
	GPIOB->BSRR |= GPIO_PIN_5; 

	GPIOC->ODR = LCD_Reg; 
	GPIOB->BRR |= GPIO_PIN_5; 
	__nop();
	__nop();
	__nop();
	GPIOB->BSRR |= GPIO_PIN_5;
	GPIOB->BSRR |= GPIO_PIN_8;

	LCD_BusIn();
	GPIOA->BRR |= GPIO_PIN_8;	
	__nop();
	__nop();
	__nop();
	temp = GPIOC->IDR;    
	GPIOA->BSRR |= GPIO_PIN_8;

	LCD_BusOut();
	GPIOB->BSRR |= GPIO_PIN_9; 

	return temp;
}
void LCD_WriteRAM_Prepare(void)
{ 
	GPIOB->BRR  |=  GPIO_PIN_9;  
	GPIOB->BRR  |=  GPIO_PIN_8; 
	GPIOB->BSRR |=  GPIO_PIN_5; 

	GPIOC->ODR = R34;     
	GPIOB->BRR  |=  GPIO_PIN_5; 
	__nop();
	__nop();
	__nop();    
	GPIOB->BSRR |=  GPIO_PIN_5;
	GPIOB->BSRR |=  GPIO_PIN_8; 
	__nop();
	__nop();
	__nop();  
	GPIOB->BSRR |=  GPIO_PIN_9; 
}
void LCD_WriteRAM(u16 RGB_Code)
{
	GPIOB->BRR  |=  GPIO_PIN_9;  
	GPIOB->BSRR |=  GPIO_PIN_8; 
	GPIOB->BSRR |=  GPIO_PIN_5; 

	GPIOC->ODR = RGB_Code;
	GPIOB->BRR  |=  GPIO_PIN_5;
	__nop();
	__nop();
	__nop();  
	GPIOB->BSRR |=  GPIO_PIN_5; 
	GPIOB->BSRR |=  GPIO_PIN_8; 
	__nop();
	__nop();
	__nop();
	GPIOB->BSRR |=  GPIO_PIN_9; 
}
u16 LCD_ReadRAM(void)
{
	u16 temp;

	GPIOB->BRR  |=  GPIO_PIN_9; 
	GPIOB->BRR  |=  GPIO_PIN_8; 
	GPIOB->BSRR |=  GPIO_PIN_5; 

	GPIOC->ODR = R34;     
	GPIOB->BRR  |=  GPIO_PIN_5;  
	__nop();
	__nop();
	__nop();  
	GPIOB->BSRR |=  GPIO_PIN_5; 
	GPIOB->BSRR |=  GPIO_PIN_8; 

	LCD_BusIn();
	GPIOA->BRR |=  GPIO_PIN_8;
	__nop();
	__nop();
	__nop();  	
	temp = GPIOC->IDR;  
	GPIOA->BSRR |=  GPIO_PIN_8;	
	
	LCD_BusOut();
	GPIOB->BSRR |=  GPIO_PIN_9; 
                         
	return temp;
}
void LCD_PowerOn(void)
{
	LCD_WriteReg(R16, 0x0000);
	LCD_WriteReg(R17, 0x0000); 
	LCD_WriteReg(R18, 0x0000);
	LCD_WriteReg(R19, 0x0000); 
	Delay_LCD(20);             
	LCD_WriteReg(R16, 0x17B0); 
	LCD_WriteReg(R17, 0x0137);
	Delay_LCD(5);             
	LCD_WriteReg(R18, 0x0139); 
	Delay_LCD(5);             
	LCD_WriteReg(R19, 0x1d00); 
	LCD_WriteReg(R41, 0x0013); 
	Delay_LCD(5);             
	LCD_WriteReg(R7, 0x0173);
}
void LCD_DisplayOn(void)
{
	LCD_WriteReg(R7, 0x0173);
}
void LCD_DisplayOff(void)
{
	LCD_WriteReg(R7, 0x0); 
}
void LCD_CtrlLinesConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
	
	GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 

	GPIO_InitStruct.Pin =  GPIO_PIN_8 ;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 

	LCD_BusOut();

	GPIOA->BSRR |= 0x0100;
	GPIOB->BSRR |= 0x0220;
}

void LCD_BusIn(void)
{	
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	GPIO_InitStruct.Pin = GPIO_PIN_All;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 		
}

void LCD_BusOut(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	GPIO_InitStruct.Pin = GPIO_PIN_All;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 	
}

void LCD_DrawPicture(const u8* picture)
{
	int index;
	LCD_SetCursor(0x00, 0x0000); 

	LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */

	for(index = 0; index < 76800; index++)
	{
		LCD_WriteRAM(picture[2*index+1]<<8|picture[2*index]);	
	}
}

bsp_lcd.h
#ifndef __LCD_H
#define __LCD_H

/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* LCD Registers */
#define R0             0x00
#define R1             0x01
#define R2             0x02
#define R3             0x03
#define R4             0x04
#define R5             0x05
#define R6             0x06
#define R7             0x07
#define R8             0x08
#define R9             0x09
#define R10            0x0A
#define R12            0x0C
#define R13            0x0D
#define R14            0x0E
#define R15            0x0F
#define R16            0x10
#define R17            0x11
#define R18            0x12
#define R19            0x13
#define R20            0x14
#define R21            0x15
#define R22            0x16
#define R23            0x17
#define R24            0x18
#define R25            0x19
#define R26            0x1A
#define R27            0x1B
#define R28            0x1C
#define R29            0x1D
#define R30            0x1E
#define R31            0x1F
#define R32            0x20
#define R33            0x21
#define R34            0x22
#define R36            0x24
#define R37            0x25
#define R40            0x28
#define R41            0x29
#define R43            0x2B
#define R45            0x2D
#define R48            0x30
#define R49            0x31
#define R50            0x32
#define R51            0x33
#define R52            0x34
#define R53            0x35
#define R54            0x36
#define R55            0x37
#define R56            0x38
#define R57            0x39
#define R59            0x3B
#define R60            0x3C
#define R61            0x3D
#define R62            0x3E
#define R63            0x3F
#define R64            0x40
#define R65            0x41
#define R66            0x42
#define R67            0x43
#define R68            0x44
#define R69            0x45
#define R70            0x46
#define R71            0x47
#define R72            0x48
#define R73            0x49
#define R74            0x4A
#define R75            0x4B
#define R76            0x4C
#define R77            0x4D
#define R78            0x4E
#define R79            0x4F
#define R80            0x50
#define R81            0x51
#define R82            0x52
#define R83            0x53
#define R96            0x60
#define R97            0x61
#define R106           0x6A
#define R118           0x76
#define R128           0x80
#define R129           0x81
#define R130           0x82
#define R131           0x83
#define R132           0x84
#define R133           0x85
#define R134           0x86
#define R135           0x87
#define R136           0x88
#define R137           0x89
#define R139           0x8B
#define R140           0x8C
#define R141           0x8D
#define R143           0x8F
#define R144           0x90
#define R145           0x91
#define R146           0x92
#define R147           0x93
#define R148           0x94
#define R149           0x95
#define R150           0x96
#define R151           0x97
#define R152           0x98
#define R153           0x99
#define R154           0x9A
#define R157           0x9D
#define R192           0xC0
#define R193           0xC1
#define R227           0xE3
#define R229           0xE5
#define R231           0xE7
#define R239           0xEF

/* LCD Control pins */
//#define CtrlPin_NCS    GPIO_Pin_9   /* PB.9 */
//#define CtrlPin_RS     GPIO_Pin_8   /* PB.8 */
//#define CtrlPin_NWR    GPIO_Pin_5  /* Pb.5 */
//#define CtrlPin_NRD    GPIO_Pin_10  /* Pb.10 */

/* LCD color */
#define White          0xFFFF
#define Black          0x0000
#define Grey           0xF7DE
#define Blue           0x001F
#define Blue2          0x051F
#define Red            0xF800
#define Magenta        0xF81F
#define Green          0x07E0
#define Cyan           0x7FFF
#define Yellow         0xFFE0

#define Line0          0
#define Line1          24
#define Line2          48
#define Line3          72
#define Line4          96
#define Line5          120
#define Line6          144
#define Line7          168
#define Line8          192
#define Line9          216

#define Horizontal     0x00
#define Vertical       0x01


/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/*----- High layer function -----*/
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;
typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;
typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;
typedef const uint32_t uc32;  /*!< Read Only */
typedef const uint16_t uc16;  /*!< Read Only */
typedef const uint8_t uc8;   /*!< Read Only */



void LCD_Init(void);
void LCD_SetTextColor(vu16 Color);
void LCD_SetBackColor(vu16 Color);
void LCD_ClearLine(u8 Line);
void LCD_Clear(u16 Color);
void LCD_SetCursor(u8 Xpos, u16 Ypos);
void LCD_DrawChar(u8 Xpos, u16 Ypos, uc16 *c);
void LCD_DisplayChar(u8 Line, u16 Column, u8 Ascii);
void LCD_DisplayStringLine(u8 Line, u8 *ptr);
void LCD_SetDisplayWindow(u8 Xpos, u16 Ypos, u8 Height, u16 Width);
void LCD_WindowModeDisable(void);
void LCD_DrawLine(u8 Xpos, u16 Ypos, u16 Length, u8 Direction);
void LCD_DrawRect(u8 Xpos, u16 Ypos, u8 Height, u16 Width);
void LCD_DrawCircle(u8 Xpos, u16 Ypos, u16 Radius);
void LCD_DrawMonoPict(uc32 *Pict);
void LCD_WriteBMP(u32 BmpAddress);
void LCD_DrawBMP(u32 BmpAddress);
void LCD_DrawPicture(const u8* picture);

/*----- Medium layer function -----*/
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue);
u16 LCD_ReadReg(u8 LCD_Reg);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(u16 RGB_Code);
u16 LCD_ReadRAM(void);
void LCD_PowerOn(void);
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);

/*----- Low layer function -----*/
void LCD_CtrlLinesConfig(void);

void LCD_BusIn(void);
void LCD_BusOut(void);


#endif /* __LCD_H */

/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

2.KEY+LED模块

bsp_key_led.c
#include "KEY_LED\bsp_key_led.h"


void KEY_LED_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);

  /*Configure GPIO pins : PC13 PC14 PC15 PC8
                           PC9 PC10 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB1 PB2 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PD2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

	//**将所有的灯熄灭
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
												|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);		
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}


//LED扫描   
void LED_Disp(uint8_t ucLed)
{
	//**将所有的灯熄灭
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
												|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);		
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);

	//根据ucLed的数值点亮相应的灯
	HAL_GPIO_WritePin(GPIOC, ucLed<<8, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);		
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);	
	
}


//按键扫描
//通过各个按键对应的引脚判断是按键几被按下
uint8_t Key_Scan(void)
{
	uint8_t unKey_Val = 0;
	
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET)
		unKey_Val = 1;

	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET)
		unKey_Val = 2;

	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET)
		unKey_Val = 3;
	
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
		unKey_Val = 4;	
	
	return unKey_Val;
}

bsp_key_led.h
#include "main.h"


void KEY_LED_Init(void);
void LED_Disp(uint8_t ucLed);
uint8_t Key_Scan(void);

3.RTC模块

bsp_rtc.c
#include "RTC\bsp_rtc.h"

RTC_HandleTypeDef hrtc;

/* RTC init function */
void RTC_Init(void)
{


  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};


  /** Initialize RTC Only
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 125;
  hrtc.Init.SynchPrediv = 6000;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initialize RTC and set the Time and Date
  */
  sTime.Hours = 23;
  sTime.Minutes = 59;
  sTime.Seconds = 55;
  sTime.SubSeconds = 0;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }
  sDate.WeekDay = RTC_WEEKDAY_FRIDAY;
  sDate.Month = RTC_MONTH_SEPTEMBER;
  sDate.Date = 10;
  sDate.Year = 21;

  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }


}

void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{

  if(rtcHandle->Instance==RTC)
  {
    /* RTC clock enable */
    __HAL_RCC_RTC_ENABLE();

  }
}

bsp_rtc.h
#include "main.h"
extern RTC_HandleTypeDef hrtc;
void RTC_Init(void);

4.ADC模块

ADC的读取函数uint16_t getADC1(void)uint16_t getADC2(void)需要手动加入

使用HAL_ADC_Start HAL_ADC_GetValue,传入对应的句柄以此读取ADC

bsp.adc.c
#include "ADC\bsp_adc.h"

ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;

/* ADC1 init function */
void ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_11;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}
/* ADC2 init function */
void ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */
  /** Common config
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.GainCompensation = 0;
  hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc2.Init.LowPowerAutoWait = DISABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc2.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_15;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */

  /* USER CODE END ADC2_Init 2 */

}

static uint32_t HAL_RCC_ADC12_CLK_ENABLED=0;

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */

  /* USER CODE END ADC1_MspInit 0 */
    /* ADC1 clock enable */
    HAL_RCC_ADC12_CLK_ENABLED++;
    if(HAL_RCC_ADC12_CLK_ENABLED==1){
      __HAL_RCC_ADC12_CLK_ENABLE();
    }

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**ADC1 GPIO Configuration
    PB12     ------> ADC1_IN11
    */
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN ADC1_MspInit 1 */

  /* USER CODE END ADC1_MspInit 1 */
  }
  else if(adcHandle->Instance==ADC2)
  {
  /* USER CODE BEGIN ADC2_MspInit 0 */

  /* USER CODE END ADC2_MspInit 0 */
    /* ADC2 clock enable */
    HAL_RCC_ADC12_CLK_ENABLED++;
    if(HAL_RCC_ADC12_CLK_ENABLED==1){
      __HAL_RCC_ADC12_CLK_ENABLE();
    }

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**ADC2 GPIO Configuration
    PB15     ------> ADC2_IN15
    */
    GPIO_InitStruct.Pin = GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN ADC2_MspInit 1 */

  /* USER CODE END ADC2_MspInit 1 */
  }
}




//***需要手敲
uint16_t getADC1(void)
{
	uint16_t adc = 0;
	
	HAL_ADC_Start(&hadc1);
	adc = HAL_ADC_GetValue(&hadc1);
	
	return adc;
}
uint16_t getADC2(void)
{
	uint16_t adc = 0;
	
	HAL_ADC_Start(&hadc2);
	adc = HAL_ADC_GetValue(&hadc2);
	
	return adc;
}

bsp.adc.h
#include "main.h"


extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;


void ADC1_Init(void);
void ADC2_Init(void);

uint16_t getADC1(void);
uint16_t getADC2(void);

5.UART模块

bsp_uart.c
#include "UART\bsp_uart.h"


UART_HandleTypeDef huart1;


void UART1_Init(void)
{

  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {

    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);

  }
}

bsp_uart.h
#include "main.h"

extern UART_HandleTypeDef huart1;

void UART1_Init(void);

6.RCC模块

bsp_rcc.c
#include "RCC\bsp_rcc.h"
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};	
  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
	 /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOF_CLK_ENABLE();//对外部晶振引脚时钟的初始化	
	//**当使用到串口1,ADC和RTC的时候,需要从此处配置时钟**//
	/** Initializes the peripherals clocks*/
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_ADC12|RCC_PERIPHCLK_RTC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_PLL;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV32;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }	
}

bsp_rcc.h
#include "main.h"

void SystemClock_Config(void);

7.i2c模块

以下代码比赛时直接从比赛给的资料里面移植24C02的相关代码和MCP4017的相关代码需要手动加入

1.24C02

24C02存储器基本原理-写操作程序分析

A.AT24C02写的函数是void iic_24c02_write(uint8_t *pucBuf, uint8_t ucAddr, uint8_t ucNum)

B.函数的入口参数分别是(要写的内容的数组,写入的地址,写入的个数)

C.根据图3.18分析写页面的时序

a.先发送开始信号

b.写入器件地址

c.等待反馈

d.发送要写字节的地址

e.继续反馈

f.使用循环连续发送字节

g.发送停止表示写操作已经完成了

24C02存储器基本原理-读操作程序分析

最常使用的读方式是随机读+顺序读

A.AT24C02读的函数是void iic_24c02_read(uint8_t *pucBuf, uint8_t ucAddr, uint8_t ucNum)

B.函数的入口参数分别是(内容读出之后放入的数组,要读出内容的地址,读出的个数)

C.根据图3.1分析写页面的时序

a.发送开始信号

d.发送器件地址--以写的形式访问的

c.等待反馈

d.发送要读字节的地址

e.继续反馈

f.发送器件地址--以读的形式访问的

g.使用循环连续读出字节

h.发送停止表示读操作已经完成了

2.MCP4017

MCP4017写可编程电阻原理

A.AT24C02写的函数是void write_resistor(uint8_t value)

B.函数的入口参数是(可编程电阻的数值)

C.根据上图分析

a.发送开始信号

a.写入器件地址

b.写入要配置的可编程电阻的数值NN的范围是0~127,数值的大小正比于电阻值的大小)

MCP4017读可编程电阻原理

A.AT24C02读的函数是uint8_t read_resistor(void)

B.根据上图分析

a.发送开始信号

b.用读的形式访问器件地址

c.读入当前的数值

d.发送接收到的信号

e.发送停止信号

3.程序源码
bsp_i2c.c

#include "I2C\bsp_i2c.h"

#define DELAY_TIME	20

/**
  * @brief SDA线输入模式配置
  * @param None
  * @retval None
  */
void SDA_Input_Mode()
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    GPIO_InitStructure.Pin = GPIO_PIN_7;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
  * @brief SDA线输出模式配置
  * @param None
  * @retval None
  */
void SDA_Output_Mode()
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    GPIO_InitStructure.Pin = GPIO_PIN_7;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
  * @brief SDA线输出一个位
  * @param val 输出的数据
  * @retval None
  */
void SDA_Output( uint16_t val )
{
    if ( val )
    {
        GPIOB->BSRR |= GPIO_PIN_7;
    }
    else
    {
        GPIOB->BRR |= GPIO_PIN_7;
    }
}

/**
  * @brief SCL线输出一个位
  * @param val 输出的数据
  * @retval None
  */
void SCL_Output( uint16_t val )
{
    if ( val )
    {
        GPIOB->BSRR |= GPIO_PIN_6;
    }
    else
    {
        GPIOB->BRR |= GPIO_PIN_6;
    }
}

/**
  * @brief SDA输入一位
  * @param None
  * @retval GPIO读入一位
  */
uint8_t SDA_Input(void)
{
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_SET){
		return 1;
	}else{
		return 0;
	}
}


/**
  * @brief I2C的短暂延时
  * @param None
  * @retval None
  */
static void delay1(unsigned int n)
{
    uint32_t i;
    for ( i = 0; i < n; ++i);
}

/**
  * @brief I2C起始信号
  * @param None
  * @retval None
  */
void I2CStart(void)
{
    SDA_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SDA_Output(0);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);
}

/**
  * @brief I2C结束信号
  * @param None
  * @retval None
  */
void I2CStop(void)
{
    SCL_Output(0);
    delay1(DELAY_TIME);
    SDA_Output(0);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SDA_Output(1);
    delay1(DELAY_TIME);

}

/**
  * @brief I2C等待确认信号
  * @param None
  * @retval None
  */
unsigned char I2CWaitAck(void)
{
    unsigned short cErrTime = 5;
    SDA_Input_Mode();
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    while(SDA_Input())
    {
        cErrTime--;
        delay1(DELAY_TIME);
        if (0 == cErrTime)
        {
            SDA_Output_Mode();
            I2CStop();
            return ERROR;
        }
    }

    SCL_Output(0);
    delay1(DELAY_TIME);
    SDA_Output_Mode();		
    return SUCCESS;
}

/**
  * @brief I2C发送确认信号
  * @param None
  * @retval None
  */
void I2CSendAck(void)
{
    SDA_Output(0);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);

}

/**
  * @brief I2C发送非确认信号
  * @param None
  * @retval None
  */
void I2CSendNotAck(void)
{
    SDA_Output(1);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);

}

/**
  * @brief I2C发送一个字节
  * @param cSendByte 需要发送的字节
  * @retval None
  */
void I2CSendByte(unsigned char cSendByte)
{
    unsigned char  i = 8;
    while (i--)
    {
        SCL_Output(0);
        delay1(DELAY_TIME);
        SDA_Output(cSendByte & 0x80);
        delay1(DELAY_TIME);
        cSendByte += cSendByte;
        delay1(DELAY_TIME);
        SCL_Output(1);
        delay1(DELAY_TIME);
    }
    SCL_Output(0);
    delay1(DELAY_TIME);
}

/**
  * @brief I2C接收一个字节
  * @param None
  * @retval 接收到的字节
  */
unsigned char I2CReceiveByte(void)
{
    unsigned char i = 8;
    unsigned char cR_Byte = 0;
    SDA_Input_Mode();
    while (i--)
    {
        cR_Byte += cR_Byte;
        SCL_Output(0);
        delay1(DELAY_TIME);
        delay1(DELAY_TIME);
        SCL_Output(1);
        delay1(DELAY_TIME);
        cR_Byte |=  SDA_Input();
    }
    SCL_Output(0);
    delay1(DELAY_TIME);
    SDA_Output_Mode();
    return cR_Byte;
}

//
void I2CInit(void)
{
		GPIO_InitTypeDef GPIO_InitStructure = {0};

    GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_6;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}


//增加自己的代码,需要手动写


//24C02的相关代码
void iic_24c02_write(uint8_t *pucBuf, uint8_t ucAddr, uint8_t ucNum)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(ucAddr);	
	I2CWaitAck();
	
	while(ucNum--)
	{
		I2CSendByte(*pucBuf++);
		I2CWaitAck();	
	}
	I2CStop();
	delay1(500);	
}


void iic_24c02_read(uint8_t *pucBuf, uint8_t ucAddr, uint8_t ucNum)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(ucAddr);	
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	while(ucNum--)
	{
		*pucBuf++ = I2CReceiveByte();
		if(ucNum)
			I2CSendAck();	
		else
			I2CSendNotAck();
	}
	I2CStop();	
}

//MCP4017的相关代码
void write_resistor(uint8_t value)
{
	I2CStart();
	I2CSendByte(0x5E);
	I2CWaitAck();
	
	I2CSendByte(value);
	I2CWaitAck();	
	I2CStop();	
}

uint8_t read_resistor(void)
{
	uint8_t value;
	I2CStart();
	I2CSendByte(0x5F);
	I2CWaitAck();
	
	value = I2CReceiveByte();
	I2CSendNotAck();	
	I2CStop();	
	
	return value;
}

bsp_i2c.h
#include "main.h"

void I2CStart(void);
void I2CStop(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(void);
void I2CSendNotAck(void);
void I2CSendByte(unsigned char cSendByte);
unsigned char I2CReceiveByte(void);
void I2CInit(void);

//24C02的相关代码
void iic_24c02_write(uint8_t *pucBuf, uint8_t ucAddr, uint8_t ucNum);
void iic_24c02_read(uint8_t *pucBuf, uint8_t ucAddr, uint8_t ucNum);

//MCP4017的相关代码
void write_resistor(uint8_t value);
uint8_t read_resistor(void);

(3)HAL

1.在stm32g4xx_hal_conf.h里面打开使用到的宏定义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值