配置 PWM ADC LCD

This commit is contained in:
2026-07-14 17:51:39 +08:00
parent 0a5c478a42
commit 2d0d000a38
67 changed files with 33357 additions and 911 deletions

View File

@@ -0,0 +1,172 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file adc.c
* @brief This file provides code for the configuration
* of the ADC instances.
******************************************************************************
* @attention
*
* Copyright (c) 2026 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 "adc.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
ADC_HandleTypeDef hadc1;
/* ADC1 init function */
void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
ADC_InjectionConfTypeDef sConfigInjected = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Injected Channel
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_0;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;
sConfigInjected.InjectedNbrOfConversion = 4;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_41CYCLES_5;
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T3_CC4;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
{
Error_Handler();
}
/** Configure Injected Channel
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_1;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
{
Error_Handler();
}
/** Configure Injected Channel
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_2;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_3;
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
{
Error_Handler();
}
/** Configure Injected Channel
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_3;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_4;
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**ADC1 GPIO Configuration
PA0-WKUP ------> ADC1_IN0
PA1 ------> ADC1_IN1
PA2 ------> ADC1_IN2
PA3 ------> ADC1_IN3
*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspDeInit 0 */
/* USER CODE END ADC1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PA0-WKUP ------> ADC1_IN0
PA1 ------> ADC1_IN1
PA2 ------> ADC1_IN2
PA3 ------> ADC1_IN3
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
/* USER CODE BEGIN ADC1_MspDeInit 1 */
/* USER CODE END ADC1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

View File

@@ -47,8 +47,8 @@ void MX_GPIO_Init(void)
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);

View File

@@ -18,16 +18,19 @@
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "lcd_data.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "button_driver.h"
#include "st7735s.h"
#include "lcd.h"
/* USER CODE END Includes */
@@ -86,7 +89,9 @@ int main(void)
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* ADC 时钟预分频PCLK2 / 6 = 72/6 = 12MHz */
/* 默认 /2=36MHz 超过 14MHz 规格ADC 无法正常工作 */
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_ADCPRE) | RCC_CFGR_ADCPRE_DIV6;
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
@@ -94,18 +99,47 @@ int main(void)
MX_DMA_Init();
MX_USART1_UART_Init();
MX_SPI2_Init();
MX_TIM4_Init();
MX_ADC1_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
printf("\r\nSTM32F103C8T6 Boot OK\r\n");
button_driver_init();
st7735s_init();
st7735s_fill_screen(COLOR_RED);
HAL_Delay(500);
st7735s_fill_screen(COLOR_GREEN);
HAL_Delay(500);
st7735s_fill_screen(COLOR_BLUE);
HAL_Delay(500);
st7735s_fill_screen(COLOR_BLACK);
st7735s_draw_string(0, 0, "LCD OK", COLOR_WHITE, COLOR_BLACK);
lcd_draw_string(0, 0, "01234", COLOR_WHITE, COLOR_BLACK);
lcd_draw_string(0, 16, "LCD_OK", COLOR_WHITE, COLOR_BLACK);
lcd_draw_chinese_string(0, 32, "\xE9\x98\x9C\xE9\x98\xB3\xE5\xB8\x88\xE8\x8C\x83\xE5\xA4\xA7\xE5\xAD\xA6", COLOR_WHITE, COLOR_BLACK); /*阜阳师范大学*/
lcd_draw_chinese_string(0, 48, "\xE7\x94\xB5\xE5\xAD\x90\xE8\xAE\xBE\xE8\xAE\xA1\xE7\xAB\x9E\xE8\xB5\x9B", COLOR_WHITE, COLOR_BLACK); /*电子设计竞赛*/
/* 启动 TIM4 四路 PWM */
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); /* PB6 */
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2); /* PB7 */
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3); /* PB8 */
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4); /* PB9 */
/* 设置占空比0~999 对应 0%~100% */
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 500); /* 50% */
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 250); /* 25% */
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, 750); /* 75% */
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, 999); /* 100% */
/* === 测试:常规组软件触发,确认 ADC 硬件正常 === */
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) {
printf("ADC REG TEST: %d\r\n", HAL_ADC_GetValue(&hadc1));
}
HAL_ADC_Stop(&hadc1);
/* 启动 TIM3 CH4产生 ADC 触发信号) */
HAL_TIM_OC_Start(&htim3, TIM_CHANNEL_4);
/* 启动 ADC 注入组TIM3 每触发一次,自动采一轮 PA0~PA3 */
HAL_ADCEx_InjectedStart(&hadc1);
/* USER CODE END 2 */
/* Infinite loop */
@@ -115,9 +149,15 @@ int main(void)
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(500);
HAL_Delay(1000);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
//printf("Hello word\n");
/* 读取 ADC 注入组结果TIM3 以 1kHz 触发,每秒打印一次最新值) */
uint16_t adc0 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_1);
uint16_t adc1 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_2);
uint16_t adc2 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_3);
uint16_t adc3 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_4);
printf("ADC: %4d %4d %4d %4d\r\n", adc0, adc1, adc2, adc3);
}
/* USER CODE END 3 */
}
@@ -130,6 +170,7 @@ void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
@@ -159,6 +200,12 @@ void SystemClock_Config(void)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */

View File

@@ -42,8 +42,8 @@ void MX_SPI2_Init(void)
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;

View File

@@ -0,0 +1,239 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file tim.c
* @brief This file provides code for the configuration
* of the TIM instances.
******************************************************************************
* @attention
*
* Copyright (c) 2026 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 "tim.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim4;
/* TIM3 init function */
void MX_TIM3_Init(void)
{
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 71;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */
/* 注意:若从 CubeMX 重新生成,务必在 TIM3 CH4 的 OC Mode 选 PWM1Pulse 设 500
否则 ADC 注入组外部触发无法工作。
此处手动修改 sConfigOC.OCMode 和 sConfigOC.Pulse 为 PWM1/500 */
/* USER CODE END TIM3_Init 2 */
}
/* TIM4 init function */
void MX_TIM4_Init(void)
{
/* USER CODE BEGIN TIM4_Init 0 */
/* USER CODE END TIM4_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM4_Init 1 */
/* USER CODE END TIM4_Init 1 */
htim4.Instance = TIM4;
htim4.Init.Prescaler = 71;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 999;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
sConfigOC.Pulse = 0;
if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
sConfigOC.Pulse = 500;
if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM4_Init 2 */
/* USER CODE END TIM4_Init 2 */
HAL_TIM_MspPostInit(&htim4);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspInit 0 */
/* USER CODE END TIM3_MspInit 0 */
/* TIM3 clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* USER CODE BEGIN TIM3_MspInit 1 */
/* USER CODE END TIM3_MspInit 1 */
}
else if(tim_baseHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspInit 0 */
/* USER CODE END TIM4_MspInit 0 */
/* TIM4 clock enable */
__HAL_RCC_TIM4_CLK_ENABLE();
/* USER CODE BEGIN TIM4_MspInit 1 */
/* USER CODE END TIM4_MspInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspPostInit 0 */
/* USER CODE END TIM4_MspPostInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM4 GPIO Configuration
PB6 ------> TIM4_CH1
PB7 ------> TIM4_CH2
PB8 ------> TIM4_CH3
PB9 ------> TIM4_CH4
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN TIM4_MspPostInit 1 */
/* USER CODE END TIM4_MspPostInit 1 */
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspDeInit 0 */
/* USER CODE END TIM3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM3_CLK_DISABLE();
/* USER CODE BEGIN TIM3_MspDeInit 1 */
/* USER CODE END TIM3_MspDeInit 1 */
}
else if(tim_baseHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspDeInit 0 */
/* USER CODE END TIM4_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM4_CLK_DISABLE();
/* USER CODE BEGIN TIM4_MspDeInit 1 */
/* USER CODE END TIM4_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

View File

@@ -117,6 +117,33 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
/* 引入标准输入输出头文件包含fputc函数原型和FILE类型定义 */
#include <stdio.h>
/* 禁用半主机模式
* 不勾选MicroLIB时标准库默认使用半主机(Semihosting)实现printf。
* 半主机需要调试器支持,脱机运行时会导致程序卡死。
* __use_no_semihosting 让链接器不链接半主机相关函数,
* 同时我们必须提供_sys_exit等替代函数。
*/
#pragma import(__use_no_semihosting)
/* 标准库要求提供 __FILE 结构体定义和 __stdout 实例 */
struct __FILE {
int handle;
};
FILE __stdout;
/* 退出函数 — 标准库在用完 _sys_exit 后调用,此处空实现 */
void _sys_exit(int return_code)
{
(void)return_code;
while (1);
}
/* 写字符 — 底层 tty 输出钩子,供某些 stdio 函数调用 */
void _ttywrch(int ch)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
}
/**
* @brief 重定向fputc函数将printf输出重定向到串口1
* @param ch: 要发送的字符
@@ -127,16 +154,16 @@ int fputc(int ch, FILE *f)
{
/* 消除未使用参数f的编译警告 */
(void)f;
/* 调用HAL库串口发送函数发送单个字符 */
/* 参数说明:
&huart1: 串口1的句柄若使用其他串口改为对应的句柄如&huart2
(uint8_t *)&ch: 要发送的数据缓冲区地址
1: 发送数据的长度(单个字符)
HAL_MAX_DELAY: 超时时间(无限等待,确保发送成)
HAL_MAX_DELAY: 超时时间(无限等待,确保发送成
*/
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
/* 返回发送的字符符合fputc函数的返回值要求 */
return ch;
}