蓝桥杯嵌入式第六届真题(完成)STM32G431

蓝桥杯嵌入式第六届真题(完成)STM32G431

题目部分

image-20240131021944807

image-20240131021954358

image-20240131022003532

image-20240131022011969

相关文件

main.c
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "i2c_hal.h"
#include "key.h"
#include "myadc.h"
#include "led.h"
#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
uint8_t lcdtext[30];
extern struct Key key[4];
uint8_t view = 0;//鍒濆lcd鏄剧ず
RTC_TimeTypeDef Time;
RTC_DateTypeDef Date;
uint8_t h=0,m=0,s=0;
float val;
float k = 0.1;
uint8_t ledflag = 1;
uint8_t ledtimes;
extern unsigned char Recive_Data[5];
extern unsigned char Temp_Data[1];
extern bool rxflag;
extern unsigned char rx_pointer;
uint32_t counter = 0;
bool ledState = false;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void key_process(void);
void lcd_process(void);
void led_process(void);
void rx_process(void);
void tx_process(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_ADC2_Init();
  MX_RTC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
		HAL_TIM_Base_Start_IT(&htim2);
		HAL_UART_Receive_IT(&huart1, Temp_Data, 1);
    LCD_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    LCD_Clear(Black);
    LCD_SetBackColor(Black);
    LCD_SetTextColor(White);
	  //EEPROM_Write_Float(0,0.9);
		//HAL_Delay(5);
    while (1)
    {
      lcd_process();
      //EEPROM_Write(0,20);
      // HAL_RTC_GetDate(&hrtc,&Date,RTC_FORMAT_BIN);
      // HAL_RTC_GetTime(&hrtc,&Time,RTC_FORMAT_BIN);
      // sprintf((char *)lcdtext,"%.2f",get_adc(&hadc2));
      // LCD_DisplayStringLine(Line2,lcdtext);
      // sprintf((char *)lcdtext,"%02d-%02d-%02d",Time.Hours,Time.Minutes,Time.Seconds);
      // LCD_DisplayStringLine(Line4,lcdtext);
			key_process();
      led_process();
      rx_process();
			tx_process();
      
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    }
  /* USER CODE END 3 */
}

/**
  * @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_HSI|RCC_OSCILLATORTYPE_LSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
  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();
  }
  /** Initializes the peripherals clocks
  */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART1
                              |RCC_PERIPHCLK_ADC12;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;

  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void key_process(void)
{
  if(key[0].key_flag==1&&view==0)
  {
    LCD_Clear(Black);
    key[0].key_flag=0;
    view = 1;
    ledflag = 0;
  }
  else if(key[0].key_flag==1&&view==1)
  {
    LCD_Clear(Black);
    key[0].key_flag=0;
    view = 0;
    ledflag = 1;
  }
  if(key[1].key_flag==1&&(view==0||view==1))
  {
    LCD_Clear(Black);
    key[1].key_flag=0;
    view = 2;

  }
	if(key[1].key_flag==1&&(view==3||view==4||view==5))
  {
    LCD_Clear(Black);
    key[1].key_flag=0;
    view = 0;

  }
  if(key[2].key_flag==1&&(view==2||view==3||view==4||view==5))
  {
    LCD_Clear(Black);
    key[2].key_flag=0;
    view++;
    if(view>5)
    {
      view = 3;
    }
  }
  if(key[3].key_flag==1&&view==3)
  {
    LCD_Clear(Black);
    key[3].key_flag=0;
    h++;
    if(h>24)
    {
      h=0;
    }
  }
  else if (key[3].key_flag==1&&view==4)
  {
    LCD_Clear(Black);
    key[3].key_flag=0;
    m++;
    if(m>60)
    {
      m=0;
    }
  }
  else if (key[3].key_flag==1&&view==5)
  {
    LCD_Clear(Black);
    key[3].key_flag=0;
    s++;
    if(s>60)
    {
      s=0;
    }
  }
  
  
}

void lcd_process(void)
{
  
  switch (view)
  {
  case 0: //LED鎵撳紑鐣岄潰
    {
     val = get_adc(&hadc2);

    sprintf((char *)lcdtext,"    V1:%.2f  ",val);
    LCD_DisplayStringLine(Line1,lcdtext);

    sprintf((char *)lcdtext,"    K:%.1f  ",EEPROM_Read_Float(0));
    LCD_DisplayStringLine(Line3,lcdtext);

    sprintf((char *)lcdtext,"    LED:ON  ");
    LCD_DisplayStringLine(Line5,lcdtext);
    HAL_RTC_GetDate(&hrtc,&Date,RTC_FORMAT_BIN);
    HAL_RTC_GetTime(&hrtc,&Time,RTC_FORMAT_BIN);
    sprintf((char *)lcdtext,"    T:%02d-%02d-%02d",Time.Hours,Time.Minutes,Time.Seconds);
    LCD_DisplayStringLine(Line7,lcdtext);
    
    }
    break;
  case 1://LED鍏抽棴鐣岄潰
    {
    val = get_adc(&hadc2);

    sprintf((char *)lcdtext,"    V1:%.2f  ",val);
    LCD_DisplayStringLine(Line1,lcdtext);

    sprintf((char *)lcdtext,"    K:%.1f  ",EEPROM_Read_Float(0));
    LCD_DisplayStringLine(Line3,lcdtext);

    sprintf((char *)lcdtext,"    LED:OFF  ");
    LCD_DisplayStringLine(Line5,lcdtext);
    HAL_RTC_GetDate(&hrtc,&Date,RTC_FORMAT_BIN);
    HAL_RTC_GetTime(&hrtc,&Time,RTC_FORMAT_BIN);
    sprintf((char *)lcdtext,"    T:%02d-%02d-%02d",Time.Hours,Time.Minutes,Time.Seconds);
    LCD_DisplayStringLine(Line7,lcdtext);
    
    }
    break;
    case 2://璁剧疆鐣岄潰
    {

    sprintf((char *)lcdtext,"       Setting  ");
    LCD_DisplayStringLine(Line3,lcdtext);

    sprintf((char *)lcdtext,"    %02d - %02d - %02d",h,m,s);
    LCD_DisplayStringLine(Line5,lcdtext);
    
    }
    break;
    case 3://璁剧疆灏忔椂鐣岄潰
    {

    sprintf((char *)lcdtext,"       Setting  ");
    LCD_DisplayStringLine(Line3,lcdtext);

    sprintf((char *)lcdtext,"    %02d - %02d - %02d",h,m,s);
    LCD_DisplayStringLine(Line5,lcdtext);
    sprintf((char *)lcdtext,"    --");
    LCD_DisplayStringLine(Line6,lcdtext);
    
    }
    break;
    case 4://璁剧疆鍒嗛挓鐣岄潰
    {

    sprintf((char *)lcdtext,"       Setting  ");
    LCD_DisplayStringLine(Line3,lcdtext);

    sprintf((char *)lcdtext,"    %02d - %02d - %02d",h,m,s);
    LCD_DisplayStringLine(Line5,lcdtext);
    sprintf((char *)lcdtext,"         --");
    LCD_DisplayStringLine(Line6,lcdtext);
    
    }
    break;
    case 5://璁剧疆绉掔晫闈?
    {

    sprintf((char *)lcdtext,"       Setting  ");
    LCD_DisplayStringLine(Line3,lcdtext);

    sprintf((char *)lcdtext,"    %02d - %02d - %02d",h,m,s);
    LCD_DisplayStringLine(Line5,lcdtext);
    sprintf((char *)lcdtext,"              --");
    LCD_DisplayStringLine(Line6,lcdtext);
    
    }
    break;
  default:
    break;
  }
    
}

void led_process(void)
{
  if (ledflag && val > 3.3f * k)
  {
    
    if (ledState)
    {
      leddisplay(0x02);
		}else{
			leddisplay(0x00);
		}
    
  }
}

void rx_process(void)
{
	if(rxflag)
	{
		if(Recive_Data[3] == '1')
		{
			k = 0.1;

			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '2')
		{
			k = 0.2;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '3')
		{
			k = 0.3;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '4')
		{
			k = 0.4;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '5')
		{
			k = 0.5;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '6')
		{
			k = 0.6;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '7')
		{
			k = 0.7;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '8')
		{
			k = 0.8;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		else if(Recive_Data[3] == '9')
		{
			k = 0.9;
			char My_sentdata[30];
			sprintf(My_sentdata,"ok\n");
			HAL_UART_Transmit(&huart1,(uint8_t*)My_sentdata,strlen(My_sentdata),50);
		}
		
		EEPROM_Write_Float(0,k);
		rx_pointer=0;
		rxflag=false; 
		memset(Recive_Data,0,5);
	}
	
}


void tx_process(void)
{
    static bool already_sent = false;

    if(Time.Hours == h && Time.Minutes == m && Time.Seconds == s)
    {
        if (!already_sent) // 检查是否已经发送过数据
        {
            char My_sentdata[30];
            sprintf(My_sentdata,"%.2f+%.1f+%02d%02d%02d\n", val, k, h, m, s);
            HAL_UART_Transmit(&huart1, (uint8_t*)My_sentdata, strlen(My_sentdata), 50);
            already_sent = true; // 标记已发送
        }
    }
    else
    {
        already_sent = false; // 当时间改变时重置标志
    }
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

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

void key_process(void);

处理按键任务,用户多个界面之间的转换以及上报时间的设置,根据当前lcd的状态,来决定按键按下的功能

void lcd_process(void);

显示各种状态,使用状态机,显示不同状态,使用sprinf函数格式化重定向字符串

void led_process(void);

控制led闪烁,使用一个计数值,在抵达定时器中++实现200ms计数

image-20240131022539272

void rx_process(void);

控制串口发送的数据,不知为何HAL_UART_Receive_IT(huart, Temp_Data, 1);中如果不是1,就会只能进入一次串口接收回调函数,所以使用每次接收一个然后设置一个缓冲区,控制指针来一次接收5个数据,只有接受完五个数据即进入5次串口接收回调函数后才执行解析函数,注意最后全波清0

void tx_process(void);

控制上报的数据,当rtc时钟的时间到达设置时间发送数据

led.c
#include "led.h"

void leddisplay(uint8_t led)
{
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOC,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);
}

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

myadc.c
#include "myadc.h"


float get_adc(ADC_HandleTypeDef *hadc)
{
	float val;
	// 等待ADC转换完成
	HAL_ADC_Start(hadc);
	val = HAL_ADC_GetValue(hadc);
	return val*3.3f/4096;
}

usart1.c
#include "usart1.h"
#include "string.h"
#include "usart.h"
#include "stdbool.h"
extern float k;
unsigned char Recive_Data[5];
unsigned char Temp_Data[1];
unsigned char rx_pointer = 0;
bool rxflag = false;
char usartsend[30];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

    
  if(huart->Instance==USART1)
	{
		Recive_Data[rx_pointer++] = Temp_Data[0];
		HAL_UART_Receive_IT(huart, Temp_Data, 1);
		if(Recive_Data[4]!=0)
		{
			rxflag = true;
		}
	
	}
}


接收完四个之后置一个标志位,rx_process才能执行,每次都需调用HAL_UART_Receive_IT函数重新开启串口接收

key.c
#include "key.h"
#include "led.h"
struct Key key[4]={0,0,0,0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		
		key[0].key_gpio = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
		key[1].key_gpio = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
		key[2].key_gpio = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
		key[3].key_gpio = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
		
		for(int i = 0; i<4;i++)
		{
			switch (key[i].key_index)
			{
			case 0:/* constant-expression */
				{
					if(key[i].key_gpio==0)
					{
						key[i].key_index = 1;
					}

				}
				break;
			case 1:
				{
					if(key[i].key_gpio==0)
					{
						key[i].key_index = 2;
						key[i].key_flag=1;
					}else{
						key[i].key_index = 0;
					}
				}
			case 2:
				{
					if(key[i].key_gpio==1)
					{
						key[i].key_index=0;
					}
				}
				break;
			}
			
		}
		
	}
}


使用状态机,第一次进入之后,进入下一个状态,如果电平还是刚刚的电平说明真的按下,如果不是重新进入第一个状态重新判断,定时器定时时间10ms刚好消抖,最后一个case2是判断如果按键松开,说明可以进入下一次判断。

i2c_hal.c
/*
  程序说明: CT117E-M4嵌入式竞赛板GPIO模拟I2C总线驱动程序
  软件环境: MDK-ARM HAL库
  硬件环境: CT117E-M4嵌入式竞赛板
  日    期: 2020-3-1
*/

#include "i2c_hal.h"
#include "main.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;
        }
    }
    SDA_Output_Mode();
    SCL_Output(0);
    delay1(DELAY_TIME);
    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);
}


void EEPROM_Write(uint8_t address,uint8_t Data)
{
	
	I2CStart();
	I2CSendByte(0xA0);
	I2CWaitAck();
	
	I2CSendByte(address);
	I2CWaitAck();
	
	I2CSendByte(Data);
	I2CWaitAck();
	
	I2CStop();
}


uint8_t EEPROM_Read(uint8_t address)
{
	uint8_t data;
	I2CStart();
	I2CSendByte(0xA0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	I2CStop();
	
	I2CStart();
	I2CSendByte(0xA1);
	I2CWaitAck();
	
	data = I2CReceiveByte();
	I2CWaitAck();
	I2CStop();
	
	
	return data;
	
}
	
	
void EEPROM_Write_Float(uint8_t address, float data)
{
    union FloatUnion fu;
    fu.floatval = data;

    for(int i = 0; i < sizeof(float); i++)
    {
        EEPROM_Write(address + i, fu.bytes[i]);
        HAL_Delay(5); 
		}
}


float EEPROM_Read_Float(uint8_t address)
{
   union FloatUnion fu;

    for(int i = 0; i < sizeof(float); i++)
    {
        fu.bytes[i] = EEPROM_Read(address + i);
    }

    return fu.floatval;
}

只有最后四个函数是本人写的,其余为蓝桥杯官方提供,主要是两种i2c时序,指定地址写和指定地址读的时序,重点在读需要首先写入要读取的地址之后再开始读,浮点数的存储使用联合体union

image-20240131023917944

floatval和bytes数组共用内存

可以看本人文章stm32教程中有对i2c四种时序的说明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/384222.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows11 MSYS2下载安装教程

MSYS2 可以理解为在windows平台上模拟linux编程环境的开源工具集 当前环境&#xff1a;windows11 1. 下载 官网地址可下载最新版本&#xff0c;需要科学上网 https://www.msys2.org/ 2. 安装 按照正常安装软件流程一路next就可以 打开 3. 配置环境 网上很多教程提到需…

基于multiprocessing.pool的多进程池与单进程访问多网页的比较示例

一、示例代码&#xff1a; from multiprocessing import Pool import time import requestsurls [ # URL队列&#xff0c;通过多进程访问http://www.python.org,http://www.python.org/about/,http://www.python.org/doc/,http…

【JavaEE】_CSS选择器

目录 1. 基本语法格式 2. 引入方式 2.1 内部样式 2.2 内联样式 2.3 外部样式 3. 基础选择器 3.1 标签选择器 3.2 类选择器 3.3 ID选择器 4. 复合选择器 4.1 后代选择器 4.2 子选择器 4.3 并集选择器 4.4 伪类选择器 1. 基本语法格式 选择器若干属性声明 2. 引入…

模拟串口LV2,解决硬件串口资源不足问题!!!!

模拟串口通信 2.0 版本&#xff01;&#xff01; 我在前面的文章里面有写了 虚拟串口通信&#xff0c;虽然说能用&#xff0c;但是用过的小伙伴都说 “好!” 优缺点: 先说一点&#xff0c;2.0版本并不适用于同硬件串口的所有场合&#xff0c;仅仅针对自己开发的电子垃圾的主…

Python - 面向对象编程 - 类变量、实例变量/类属性、实例属性

什么是对象和类 什么是 Python 类、类对象、实例对象 类变量、实例变量/类属性、实例属性 前言 只是叫法不一样 实例属性 实例变量 类属性 类变量 个人认为叫属性更恰当 类属性和实例属性区别 类属性&#xff0c;所有实例对象共享该属性实例属性&#xff0c;属于某一…

【MySQL】操作库 —— 库的操作 -- 详解

一、增删数据库 1、创建数据库 create database db_name; 本质就是在 /var/lib/mysql 创建一个目录。 说明&#xff1a; 大写的表示关键字。[ ] 是可选项。CHARACTER SET&#xff1a;指定数据库采用的字符集。COLLATE&#xff1a;指定数据库字符集的校验规则。 2、数据库删除…

Python||数据分析之pyecharts 绘图(词云、气泡)

1. echarts 和 Pyecharts 简介 1.1echarts 简介: • echarts 是一个使用 JavaScript 实现的开源可视化库,涵盖各行业图表,满足各种需求。 • echarts 遵循 Apache-2.0 开源协议,免费商用。 • ECharts 最初由百度团队开源,并于 2018 年初捐赠给 Apache 基金会,成为 AS…

算法day12

算法day12 二叉树理论基础114 二叉树的前序遍历145 二叉树的后序遍历94 二叉树的中序遍历迭代法 二叉树理论基础 直接看代码随想录就完事了&#xff0c;之前考研也学过&#xff0c;大概都能理解 我这里就说说代码层面的。 二叉树的存储&#xff1a; 1、链式存储&#xff1a;这…

内容检索(2024.02.12)

随着创作数量的增加&#xff0c;博客文章所涉及的内容越来越庞杂&#xff0c;为了更为方便地阅读&#xff0c;后续更新发布的文章将陆续在此做简介并附上原文链接&#xff0c;感兴趣的小伙伴们可持续关注文章发布动态&#xff1a; 信号仿真类话题如何看待频域与时域的仿真差别-…

猫头虎分享已解决Bug || Python Error: ImportError: No module named ‘module_name‘

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

数学建模:EWM – TOPSIS 超强讲义! 原理、应用、代码

目录 一、综合评价指标预处理 1.定量指标的一致化处理&#xff08;正向化处理&#xff09; 2.定量指标的无量纲化处理 二、熵权法&#xff08;EWM&#xff09; 三、TOPSIS法 四、熵权法-TOPSIS的使用流程 案例&#xff1a;熵权法-TOPSIS的案例分析&#xff1a;水质评价 …

贪吃蛇的实现,基于windows操作系统

前言&#xff1a; 贪吃蛇从学习到真正实现花了9天实现&#xff0c;第一二天第一次学习&#xff0c;第三四五天第二次学习&#xff0c;第六七八天一边实现一边思考&#xff0c;才完成了贪吃蛇的代码。实现了贪吃蛇以后已经接近过年&#xff0c;我想自己再根据掌握的知识制作烟花…

leetcode 461. 汉明距离

比较简单的一题&#xff0c;先对两个整数进行异或操作&#xff0c;会将两个整数二进制形式中各个数字进行异或操作&#xff0c;不同的数字则为1&#xff0c;再通过移位操作统计得到的二进制数中为1的个数&#xff0c;即为所求。 Java代码如下&#xff1a; class Solution {pub…

STM32 STD/HAL库驱动W25Q64模块读写字库数据+OLED0.96显示例程

STM32 STD/HAL库驱动W25Q64 模块读写字库数据OLED0.96显示例程 &#x1f3ac;原创作者对W25Q64保存汉字字库演示&#xff1a; W25Q64保存汉字字库 &#x1f39e;测试字体显示效果&#xff1a; &#x1f4d1;功能实现说明 利用W25Q64保存汉字字库&#xff0c;OLED显示汉字的时…

SVD奇异值分解

一、奇异值 奇异值&#xff08;Singular Values&#xff09;是线性代数中矩阵的重要性质之一&#xff0c;与奇异值分解&#xff08;SVD&#xff09;密切相关。让我们来更详细地了解一下奇异值的概念&#xff1a; 定义&#xff1a; 对于一个矩阵 ( A )&#xff0c;它的奇异值是…

【Chrono Engine学习总结】4-vehicle-4.1-vehicle的基本概念

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 1、基本介绍 Vehicle Overview Vehicle Mannel Vehicle的官方demo 1.1 Vehicle的构型 一个车辆由许多子系统构成&#xff1a;悬挂、转向、轮子/履带、刹车/油门、动…

双场板功率GaN HEMT电容模型以精确模拟开关行为

标题&#xff1a;Capacitance Modeling in Dual Field-Plate Power GaN HEMT for Accurate Switching Behavior&#xff08;TED.16年&#xff09; 摘要 本文提出了一种基于表面电位的紧凑模型&#xff0c;用于模拟具有栅极和源极场板&#xff08;FP&#xff09;结构的AlGaN/G…

JMM(Java内存模型)

Java内存模型&#xff08;Java Memory Model&#xff0c;简称JMM&#xff09;是Java语言规范中定义的一个抽象概念&#xff0c;它描述了程序中各个变量&#xff08;包括实例字段、静态字段和构成数组对象的元素&#xff09;在并发环境下的访问规则和一致性保证。JMM的主要目标是…

python+flask+django医院预约挂号病历分时段管理系统snsj0

技术栈 后端&#xff1a;python 前端&#xff1a;vue.jselementui 框架&#xff1a;django/flask Python版本&#xff1a;python3.7 数据库&#xff1a;mysql5.7 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm . 第一&#xff0c;研究分析python技术&#xff0c…

点云标注工具

目录 3d手势识别 c 3d关键点&#xff0c;Bounding Box Labels Rectangle Labels KITTI 3D Ground Truth Annotator c标注工具 3d手势识别 GitHub - 99xtaewoo/Automated-Hand-3D-pose-annotation-Tool: Automated Hand 3D pose annotation Tool c 3d关键点&#xff0c;Bou…