蓝桥杯嵌入式基本模块STM32G431RBT6介绍
一、LED灯模块
1.LED灯的原理图
2.CubeMX配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)配置LED灯引脚
由原理可知,当引脚为低电平时LED灯会亮;为高电平时LED灯会灭
首先将LED灯的引脚都使能为GPIOoutput模式
然后再设置默认为高电平
(7)创建工程
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
4. keil配置
(1)debug配置
选择CMSIS-DAP Debugger调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址
gitee地址:LCD灯模块源码地址——gitee
github地址:LCD灯模块源码地址——github
二、LCD模块
1.LCD原理图
2.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)LCD引脚配置
将LCD涉及的引脚全都使能位GPIO_Output模式(注意:LCD有些引脚是和LED的引脚重复的)
(7)创建工程
3.代码
1.lcd相关代码:
lcd.c、lcd.h和fonts.h这些是可以直接从资料包里面拷贝的
将这三个文件copy到我们自己的工程下面
4. keil配置
(1)debug配置
选择CMSIS-DAP Debugger调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址
gitee地址:LCD模块源码地址——gitee
github地址:LCD模块源码地址——github
三、定时器和按键模块
1.按键原理图
2.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)按键key的相关引脚配置
将相关的引脚使能为gpio_input模式,并且设置为上拉模式,按下时为低电平,其余时候为高电平
设置为上拉模式
(7)定时器配置
定时时间=时钟频率/((预分频系数+1)(重装载值+1))
在配置时钟树时,我们已经将时钟频率设置为80MHZ了,
则定时时间=(80000000)/((pre+1)(arr+1))
开启定时器中断
(7)创建工程
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调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址:
gitee地址:定时器和按键模块源码地址——gitee
GitHub地址:定时器和按键模块源码地址——github
四、PWM输出
1.实现功能
2.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)按键key的相关引脚配置
将相关的引脚使能为gpio_input模式,并且设置为上拉模式,按下时为低电平,其余时候为高电平
设置为上拉模式
(7)PWM输出引脚配置
定时时间=时钟频率/((预分频系数+1)(重装载值+1))
在配置时钟树时,我们已经将时钟频率设置为80MHZ了,
则定时时间=(80000000)/((pre+1)(arr+1))
PA6引脚的配置
占空比在程序中还可以调整;占空比=比较输出/自动重装载值;
调用__HAL_TIM_SetCompare可以重新设置占空比
//第一个参数:定时器句柄
//第二个参数:PWM通道数
//第三个参数:CCR,比较值
例如:__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,pa1*10/100);
PA7引脚的配置
(7)创建工程
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调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址
gitee地址:PWM输出源码地址——gitee
github地址:PWM输出源码地址——github
五、输入捕获(频率、占空比测量)
在蓝桥杯嵌入式比赛中,一般不会使用原理图中的信号发生器中的引脚,而是使用其他引脚来当作输入捕获,但在这里还是使用的信号发生器中的引脚
1.原理图
2.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)输入捕获相关引脚配置
注意:如果不需要测量占空比,只需要测频率,则不需要开启间接捕获,只需要开启通道1的直接捕获
TIM2的配置
开启定时器2的中断
TIM3配置
开启定时器3中断
(7)创建工程
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
4. keil配置
(1)debug配置
选择CMSIS-DAP Debugger调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址
gitee地址:输入捕获源码地址——gitee
github地址:输入捕获源码地址——GitHub
六、IIC通信——EEPROM读写
1.原理图
2.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)IIC相关引脚配置
(7)创建工程
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调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址
gitee地址:IIC通信源码地址——gitee
github地址:IIC通信源码地址——GitHub
七、模数转换adc
1.原理图
2.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)ADC相关引脚配置
首先使能ADC引脚
配置通道
(7)创建工程
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调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址
gitee地址:模数转换ADC源码——gitee
github地址:模式转换ADC源码——GitHub
八、串口通信
1.原理图
2.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)串口通信相关引脚配置
开启中断
创建工程
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调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
5.源码地址
gitee地址:串口通信源码地址——gitee
github地址:串口通信源码地址——GitHub
九、实时时钟(RTC)
1.CubeMx配置
(1)新建工程
(2)选择芯片型号并开始工程
(3)配置RCC为外部高速时钟
配置了RCC为外部高速时钟时,这两个引脚会被选中
(4)配置时钟树
产品手册中外部晶振时24MHZ
因此,时钟树的配置如下:
(5)设置为串行线调试(SWD)
设置之后这两个引脚会自动选中
(6)RTC相关配置
设置初始年月日时分秒
RTC时钟配置
(7)创建工程
2.代码
修改main.c
3. keil配置
(1)debug配置
选择CMSIS-DAP Debugger调试器。
然后点击Setings
在Flash Download选项卡下,勾选Reset and Run
(2)下载
4.源码地址
gitee地址:RTC源码——gitee
github地址:RTC源码——github
作者:blmeue