蓝桥杯嵌入式基本模块STM32G431RBT6介绍

一、LED灯模块


1.LED灯的原理图

LED灯的原理图

2.CubeMX配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)配置LED灯引脚
由原理可知,当引脚为低电平时LED灯会亮;为高电平时LED灯会灭
首先将LED灯的引脚都使能为GPIOoutput模式
引脚配置
然后再设置默认为高电平
默认高电平
(7)创建工程
project
Code

3.代码

(1)led.c代码

//led显示函数
//入口参数:ucled
//出口参数:void
// unsigned char :8位
//函数功能:直接让某个灯亮   LD8-LD1对应ucled的8个位
//最高位:LD8;最低位:LD1
void LED_Disp(unsigned char ucled)
{
    
    //将所有的灯熄灭
    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);   

    //根据ucled的数值点亮响应的灯
    //dsled默认在前八位,左移八位,就可以控制PC15-PC8
    //例如 dsLED=0x65,即0110 0101
    //左移八位就变成 0110 0101 0000 0000
    HAL_GPIO_WritePin(GPIOC,ucled<<8,GPIO_PIN_RESET);//有1的地方变为reset
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);      

}

(2)led.h

#ifndef __LED_H__
#define __LED_H__

#include "main.h"

void LED_Disp(uchar dsLED);

#endif

(3)main.c
main.c

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址

gitee地址:LCD灯模块源码地址——gitee
github地址:LCD灯模块源码地址——github

二、LCD模块


1.LCD原理图

LCD原理图

2.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)LCD引脚配置
将LCD涉及的引脚全都使能位GPIO_Output模式(注意:LCD有些引脚是和LED的引脚重复的)
lcd引脚配置
(7)创建工程
project
Code

3.代码

1.lcd相关代码:
lcd.c、lcd.h和fonts.h这些是可以直接从资料包里面拷贝的
1
2
将这三个文件copy到我们自己的工程下面
lcd.c
lcd.h

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址

gitee地址:LCD模块源码地址——gitee
github地址:LCD模块源码地址——github

三、定时器和按键模块


1.按键原理图

按键

2.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)按键key的相关引脚配置
将相关的引脚使能为gpio_input模式,并且设置为上拉模式,按下时为低电平,其余时候为高电平
按键引脚
设置为上拉模式
上拉

(7)定时器配置
定时时间=时钟频率/((预分频系数+1)(重装载值+1))
在配置时钟树时,我们已经将时钟频率设置为80MHZ了,
则定时时间=(80000000)/((pre+1)
(arr+1))

定时器配置
开启定时器中断
定时器中断
(7)创建工程
project
Code

3.代码

(1)timer.c代码:

#include "timer.h"

struct keys key[4]={0,0,0,0};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM2 )
    {
        //读取每个按键的状态
        key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
        key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
        key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
        key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
        
        for(int i=0;i<4;i++)
        {
            switch(key[i].judge_sta)
            {
                case 0:
                    if(key[i].key_sta==0)//被按下
                    {
                        key[i].judge_sta=1;
                    }
                    break;
                case 1://消抖
                    if(key[i].key_sta==0)
                    {
                        key[i].single_flag=1;
                        key[i].judge_sta=2;
                    }
                    else
                        key[i].judge_sta=0;
                    break;
                case 2:
                    if(key[i].key_sta==1)//松手,按键被松开,判断松手的过程
                        key[i].judge_sta=0;
                    break;
            }
        }
    }
}

(2)timer.h代码:

#ifndef __TIMER_H__
#define __TIMER_H__

#include "main.h"
#include "stdbool.h"

struct keys
{
    unsigned char judge_sta;//判断进行到哪步了
    bool key_sta;//识别到硬件按下为0
    bool single_flag;//确认被按下为1,按下标志位
};

extern struct keys key[4];
#endif

(3)main.c代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "led.h"
#include "timer.h"
#include "lcd.h"
#include "stdio.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* 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_proc(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();
  /* USER CODE BEGIN 2 */
    HAL_TIM_Base_Start_IT(&htim2);

    led_disp(0x00);
    LCD_Init();
    LCD_Clear(White);
    LCD_SetBackColor(White);
    LCD_SetTextColor(Blue2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      key_proc();
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {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();
  }
}

/* USER CODE BEGIN 4 */

void key_proc(void)
{
    unsigned char txt[30];
    if(key[0].single_flag==1)
    {
      //led_disp(0x01);
     // HAL_Delay(500);//延时500ms
     // led_disp(0x00);
     // HAL_Delay(500);//延时500ms
        led_disp(0xaa);
        sprintf((char *)txt,"%s","key0down");
        LCD_DisplayStringLine(Line7,txt);
        key[0].single_flag =0;
    }
}

/* 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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址:

gitee地址:定时器和按键模块源码地址——gitee
GitHub地址:定时器和按键模块源码地址——github

四、PWM输出

1.实现功能

PWM

2.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)按键key的相关引脚配置
将相关的引脚使能为gpio_input模式,并且设置为上拉模式,按下时为低电平,其余时候为高电平
按键引脚
设置为上拉模式
上拉

(7)PWM输出引脚配置
PWM
定时时间=时钟频率/((预分频系数+1)(重装载值+1))
在配置时钟树时,我们已经将时钟频率设置为80MHZ了,
则定时时间=(80000000)/((pre+1)
(arr+1))

PA6引脚的配置
PA6
占空比在程序中还可以调整;占空比=比较输出/自动重装载值;
调用__HAL_TIM_SetCompare可以重新设置占空比
//第一个参数:定时器句柄
//第二个参数:PWM通道数
//第三个参数:CCR,比较值
例如:__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,pa1*10/100);
占空比
PA7引脚的配置

PA7

(7)创建工程
project
Code

3.代码

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "interrupt.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern struct keys key[];//在main函数引用interrupt.c文件里的struct keys key变量

uchar view=0;//默认在第一个界面

uchar pa6_duty=10;//PA6的占空比
uchar pa7_duty=10;

void key_proc(void);
void disp_proc(void);
/* 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 */

/* 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_TIM3_Init();
  /* USER CODE BEGIN 2 */
    LED_Disp(0x00);//LED的初始化,即让所有led灭
    LCD_Init();//LCD屏的初始化

	LCD_Clear(Black);//把屏幕清空,清成黑色
	LCD_SetBackColor(Black);//设置背景色
	LCD_SetTextColor(White);//设置文本颜色(前景色)
    
	HAL_TIM_Base_Start_IT(&htim3);//开启定时器3的中断
    
    //PA6输出频率固定为100HZ,占空比可调节的脉冲信号
    //PA7输出频率固定为200HZ,占空比可调节的脉冲信号
    //打开PWM输出
    HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);//第一个参数为哪个定时器,第二个参数为通道几
    HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);//第一个参数为哪个定时器,第二个参数为通道几
    
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      LED_Disp(0x01);
      HAL_Delay(500);//延时500ms
      LED_Disp(0x00);
      HAL_Delay(500);//延时500ms
      
    key_proc();
      disp_proc();

  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {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();
  }
}

/* USER CODE BEGIN 4 */
//按键
void key_proc(void){
      if(key[0].single_flag==1){//第一个按键被按下
          view=!view;
      LCD_Clear(Black);//切换界面时要进行清屏操作,避免上一界面残留
      key[0].single_flag=0;//将按下标志位清0,避免被重复执行  
          
      }
      if(key[1].single_flag==1){//第一个按键被按下
      pa6_duty+=10;
      if(pa6_duty>=100)
          pa6_duty=10;
       //将设置的占空比应用到输出当中
      __HAL_TIM_SetCompare(&htim16,TIM_CHANNEL_1,pa6_duty);//第一个参数是哪个定时器,第二个参数是哪个通道,第三个参数是值
      LCD_Clear(Black);//切换界面时要进行清屏操作,避免上一界面残留
      key[1].single_flag=0;//将按下标志位清0,避免被重复执行  
          
      }  
      if(key[2].single_flag==1){//第一个按键被按下
      pa7_duty+=10;
      if(pa7_duty>=100)
          pa7_duty=10;
      __HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,pa7_duty);//第一个参数是哪个定时器,第二个参数是哪个通道,第三个参数是值
      LCD_Clear(Black);//切换界面时要进行清屏操作,避免上一界面残留
      key[2].single_flag=0;//将按下标志位清0,避免被重复执行  
          
      }            
}

//LCD屏显示
void disp_proc(void){
    if(view==0){
      char text[30];//字符数组
      sprintf(text,"      Data       ");
      LCD_DisplayStringLine(Line1, (uint8_t *)text);//将text里面的数据打印到第九行
    }
    if(view==1){
      char text[30];//字符数组
      sprintf(text,"      Para       ");
      LCD_DisplayStringLine(Line1, (uint8_t *)text);//将text里面的数据打印到第九行
        sprintf(text,"    PA6:%d       ",pa6_duty);
        LCD_DisplayStringLine(Line2, (uint8_t *)text);//将text里面的数据打印到第九行
        sprintf(text,"    PA7:%d       ",pa7_duty);
        LCD_DisplayStringLine(Line4, (uint8_t *)text);//将text里面的数据打印到第九行
 
    }
}

/* 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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址

gitee地址:PWM输出源码地址——gitee
github地址:PWM输出源码地址——github

五、输入捕获(频率、占空比测量)

在蓝桥杯嵌入式比赛中,一般不会使用原理图中的信号发生器中的引脚,而是使用其他引脚来当作输入捕获,但在这里还是使用的信号发生器中的引脚

1.原理图

输入捕获

2.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)输入捕获相关引脚配置
1

注意:如果不需要测量占空比,只需要测频率,则不需要开启间接捕获,只需要开启通道1的直接捕获

TIM2的配置
TIM2
开启定时器2的中断
TIM2中断
TIM3配置

开启定时器3中断

(7)创建工程
project
Code

3.代码

(1)timer.c

#include "timer.h"


struct keys key[4]={0,0,0,0};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    
    //定时器4用来扫描按键
    if(htim->Instance==TIM4)
    {
             key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
             key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
             key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
             key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
         for(int i=0;i<4;i++)
        {
           switch(key[i].judge_sta)
            {
                case 0:
                    if(0==key[i].key_sta)
                        key[i].judge_sta=1;
                    break;
                case 1:
                    if(0==key[i].key_sta)//消抖
                    {
                        key[i].single_flag=1;
                        key[i].judge_sta=2;
                    }
                    else 
                        key[i].judge_sta=0;
                    break;
                case 2:
                    if(1==key[i].key_sta)//松开按键
                    {
                        key[i].judge_sta=0;
                    }
                    break;
            }
        }
    }
}


///**********测频率-占空比***********
double ccrl_val1a=0,ccrl_val2a=0;
unsigned int ccrl_val1b=0,ccrl_val2b=0;

unsigned int frq1=0,frq2=0;//频率

float duty1=0,duty2=0;//占空比

/*
定时器的输入捕获有两个功能,直接捕获模式和间接捕获模式;
直接捕获:只能捕获本身通道的脉冲信号;

间接模式:可以捕获此定时器每个通道的脉信号。

1.捕获频率:初始化定时器基础,开启定时器,开启定时器输入捕获上升沿中断,定时器一直计数,
            直到,捕获到上升沿说明过了一个周期,读取计数值,读取完然后清零,
            等待读取下一个周期,乘以时钟频率,就是周期,然后计算PWM频率。

2.捕获占空比:利用此定时器的另一个通道,作为间接捕获模式,读取下降沿,产生下降沿中断,读取此定时器的计数值,
                就是占空比的高电平时间。


*/

//输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//定时器捕获中断回调函数
{
    //计算定时器2的频率
    if(htim->Instance==TIM2)
    {
        if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)//中断消息来源 选择直接输入的通道
        {
        //保存定时器的计数值
        ccrl_val1a=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
        ccrl_val1b=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);//读出的计数值是高电平的计数值
            
        //将定时器的计数值清0
        __HAL_TIM_SetCounter(htim,0);
        //计算频率
        frq1=(80000000/80)/ccrl_val1a;
            
        //计算占空比
         duty1=(ccrl_val1b/ccrl_val1a)*100;
            
        //重新开启定时器
        HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
        HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);

        }
    }
    
    //计算定时器3的频率
        if(htim->Instance==TIM3)
    {
          if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)//中断消息来源 选择直接输入的通道
        {
        //保存定时器的计数值
        ccrl_val2a=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
        ccrl_val2b=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);

        //将定时器的计数值清0
        __HAL_TIM_SetCounter(htim,0);
        //计算频率
        frq2=(80000000/80)/ccrl_val2a;
        
         //计算占空比
         duty2=(ccrl_val2b/ccrl_val2a)*100;   
         
        //重新开启定时器
        HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
        HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);

        }
    }
}


(2)timer.h

#ifndef __TIMER_H__
#define __TIMER_H__


#include "main.h"
#include "stdbool.h"

struct keys 
{
    unsigned char judge_sta;
    bool single_flag;
    bool key_sta;
};

extern struct keys key[4];

extern double ccrl_val1a,ccrl_val2a;
extern unsigned int ccrl_val1b,ccrl_val2b;

extern unsigned int frq1,frq2;//频率

extern float duty1,duty2;//占空比
#endif

(3)修改main.c
修改main.c

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址

gitee地址:输入捕获源码地址——gitee
github地址:输入捕获源码地址——GitHub

六、IIC通信——EEPROM读写

1.原理图

IIC原理图

2.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)IIC相关引脚配置
IIC引脚配置
(7)创建工程
project
Code

3.代码

(1)i2c_hal.c:
从资料包中的底层驱动代码参考中拷贝i2c_hal.c和i2c_hal.h,然后修改这两个文件

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

#include "i2c_hal.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);
}

//从eeprom 读
unsigned char eeprom_read(unsigned char addr)
{
    unsigned char ret;
    
    I2CStart();
    I2CSendByte(0xa0);
    I2CWaitAck();
    I2CSendByte(addr);
    I2CWaitAck();    
    I2CStop();
    
    I2CStart();
    I2CSendByte(0xa1);
    I2CWaitAck();
    ret=I2CReceiveByte();
    I2CWaitAck();    
    I2CStop();

   return ret;
}

//向eeprom写
void eeprom_write(unsigned char addr,unsigned char data)
{
    I2CStart();
    I2CSendByte(0xa0);
    I2CWaitAck();
    I2CSendByte(addr);
    I2CWaitAck(); 
    I2CSendByte(data);
    I2CWaitAck();
    I2CStop();  
}

(2)i2c_hal.h

#ifndef __I2C_HAL_H
#define __I2C_HAL_H

#include "stm32g4xx_hal.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);

unsigned char eeprom_read(unsigned char addr);
void eeprom_write(unsigned char addr,unsigned char data);

#endif

(3)main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "led.h"
#include "lcd.h"
#include "timer.h"
#include "myusart.h"
#include "i2c_hal.h"
#include "stdio.h"
#include "String.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* 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_proc(void);
void lcd_proc(void);

/* USER CODE END PFP */

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

unsigned char text[30];//保存lcd所要显示的数据
unsigned char ucled=0x00;//led灯

//减速函数,控制lcd_proc的速度
__IO uint32_t uwTick_pcd=0;

//两个通道(pa6,pa7)的占空比
unsigned char pa6_duty=10;
unsigned char pa7_duty=10;

/* 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_TIM3_Init();
  MX_TIM4_Init();
  MX_TIM16_Init();
  MX_TIM17_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

    led_disp(0X00);
    LCD_Init();
    LCD_Clear(White);
    LCD_SetBackColor(White);
    LCD_SetTextColor(Blue2);
    
    HAL_UART_Receive_IT(&huart1,&rxdat,1);//打开串口接收中断
    
    HAL_TIM_Base_Start_IT(&htim4);//使能定时器4
    
    //打开定时器PWM输出
    HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
    
    //打开定时器输入捕获
    HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
    HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
   
   
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      key_proc();
      lcd_proc();
      
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {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();
  }
}

/* USER CODE BEGIN 4 */

void key_proc(void)
{
    if(1==key[0].single_flag)
    {
        ucled=ucled|0x01;
        sprintf((char *)text,"    %s","key1down");
        LCD_DisplayStringLine(Line0 ,text);
        key[0].single_flag=0;
    }
    else if(1==key[1].single_flag)
    {
        ucled=ucled&0xfe;
        //将频率(16位)存到eeprom中
        //将频率分为高八位和低八位,分别存到eeprom中
        unsigned char frq1_h=frq1>>8;
        unsigned char frq1_l=frq1&0xff;
        eeprom_write(1,frq1_h);
        HAL_Delay(10);//十毫秒
        eeprom_write(2,frq1_l);
       sprintf((char *)text,"    %s","key2down");
        LCD_DisplayStringLine(Line0 ,text);
        key[1].single_flag=0;
    }
    else if(1==key[2].single_flag)
    {
        ucled=ucled|0x02;
        sprintf((char *)text,"    %s","key3down");
        LCD_DisplayStringLine(Line0 ,text);
        //pa6_duty增加
        pa6_duty+=10;
        if(pa6_duty>=100)pa6_duty=10;
        __HAL_TIM_SetCompare(&htim16,TIM_CHANNEL_1,pa6_duty);
        key[2].single_flag=0;
    }
    else if(1==key[3].single_flag)
    {
        ucled=ucled&0xdf;
        sprintf((char *)text,"    %s","key4down");
        LCD_DisplayStringLine(Line0 ,text);
        //pa7_duty增加
        pa7_duty+=10;
        if(pa7_duty>=100)pa7_duty=10;
        __HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,pa7_duty);

       key[3].single_flag=0;
    }
    
    led_disp(ucled);
}

void lcd_proc(void)
{
    if((uwTick-uwTick_pcd)<200)return;//减速函数
    uwTick_pcd=uwTick;
    
  //第二行显示pa6的占空比
    sprintf((char *)text,"pa6_duty:%d%%",pa6_duty);
    LCD_DisplayStringLine(Line1,text);
    
  //第三行显示pa7的占空比
    sprintf((char *)text,"pa7_duty:%d%%",pa7_duty);
    LCD_DisplayStringLine(Line2,text);
    
  //第四行显示R39(tim3)的频率frq2;
 //   sprintf((char *)text,"tim3_frq2:%05d Hz",frq2);
 //   LCD_DisplayStringLine(Line3,text);
    sprintf((char *)text,"tim2_frq:%05d Hz",frq2);
       LCD_DisplayStringLine(Line3,text);   
  //第五行显示R39(tim3)的占空比duty2; 
    sprintf((char *)text,"tim3_duty2:%0.3f%%",duty2);
    LCD_DisplayStringLine(Line4,text);    
    
  //第六行显示R40(tim2)的频率frq1;
    sprintf((char *)text,"tim2_frq1:%05d Hz",frq1);
    LCD_DisplayStringLine(Line5,text);
    
  //第七行显示R40(tim2)的占空比duty1; 
    sprintf((char *)text,"tim2_duty1:%0.3f%%",duty1);
    LCD_DisplayStringLine(Line6,text);   
    
  //读出存储在eeprom中的频率
    unsigned int eeprom_temp=(eeprom_read(1)<<8)+(eeprom_read(2));
    sprintf((char *)text,"eeprom_frq1:%05d Hz",eeprom_temp);
    LCD_DisplayStringLine(Line7,text);

}

/* 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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址

gitee地址:IIC通信源码地址——gitee
github地址:IIC通信源码地址——GitHub

七、模数转换adc

1.原理图

adc

2.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)ADC相关引脚配置
首先使能ADC引脚

ADC引脚
配置通道
ADC1
ADC2

(7)创建工程
project
Code

3. 代码

(1)myadc.c

#include "myadc.h"

//读取ADC的值
//参数是ADC的引脚
double get_adc(ADC_HandleTypeDef *pin)
{
    //读出来的原始值
    unsigned int adc;
    //开启adc
    HAL_ADC_Start(pin);
    
    //读取ADC的值
    adc=HAL_ADC_GetValue(pin);
    
    //12位精度即4096
    //4096就代表3.3V
    return adc*(3.3/4096);
    
}

(2)myadc.h

#ifndef __MYADC_H__
#define __MYADC_H__

#include "main.h"

double get_adc(ADC_HandleTypeDef *pin);

#endif

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址

gitee地址:模数转换ADC源码——gitee
github地址:模式转换ADC源码——GitHub

八、串口通信

1.原理图

串口通信

2.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)串口通信相关引脚配置
1
2
开启中断
![开中断](https://i3.wp.com/img-blog.csdnimg.cn/direct/1df08b751e904533a495883d00b178c2.png

(7)创建工程
project
Code

3.代码

(1)myusart.c

#include "myusart.h"
#include "usart.h"

char rxdata[30];//保存接收数据(从串口助手输入的数据)
unsigned char rxpointer;//表示接收了多少个字符
unsigned char rxdat;//每次接收的字符


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    rxdata[rxpointer++]=rxdat;
    HAL_UART_Receive_IT(&huart1,&rxdat,1);
}

(2)myusart.h

#ifndef __MYUSART_H__
#define __MYUSART_H__

#include "main.h"

extern char rxdata[30];
extern unsigned char rxpointer;
extern unsigned char rxdat;

#endif

(3)修改Main.c
在main函数的while(1)之前启动UART接收中断模式

修改main函数

创建usart_proc函数

//从电脑的串口助手通过串口发送消息给板子
//并返回到串口助手
void usart_proc(void)
{
    if(rxpointer!=0)//判断是否有接收到字符
    {
        rxdata[rxpointer++]='\r';
        rxdata[rxpointer++]='\n';
        
        HAL_UART_Transmit(&huart1,(uint8_t *)rxdata,strlen(rxdata),50);//将串口助手输入的字符重新发送到串口助手
        memset(rxdata,0,strlen(rxdata));
        rxpointer=0;
    }
}

4. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

5.源码地址

gitee地址:串口通信源码地址——gitee
github地址:串口通信源码地址——GitHub

九、实时时钟(RTC)

1.CubeMx配置

(1)新建工程
新建工程
(2)选择芯片型号并开始工程
创建工程
(3)配置RCC为外部高速时钟
配置RCC
配置了RCC为外部高速时钟时,这两个引脚会被选中
RCC引脚

(4)配置时钟树
产品手册中外部晶振时24MHZ
外部晶振
因此,时钟树的配置如下:
时钟树
(5)设置为串行线调试(SWD)
串行线调试
设置之后这两个引脚会自动选中
SWD引脚
(6)RTC相关配置

设置初始年月日时分秒

RTC时钟配置
RTC

(7)创建工程
project
Code

2.代码

修改main.c

3. keil配置

(1)debug配置

选择CMSIS-DAP Debugger调试器。
debug
然后点击Setings
设置
在Flash Download选项卡下,勾选Reset and Run

(2)下载
下载

4.源码地址

gitee地址:RTC源码——gitee
github地址:RTC源码——github

作者:blmeue

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯嵌入式基本模块STM32G431RBT6介绍

发表回复