proteus + keil +stm32cubemx
二、实验内容:
参考程序:
以下是基于Proteus+Keil+STM32CubeMX的嵌入式闹钟实验的参考程序,供参考学习:
1. main.c
```c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "OLED.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Private variables ---------------------------------------------------------*/
RTC_HandleTypeDef hrtc;
TIM_HandleTypeDef htim3;
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);
static void MX_RTC_Init(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
void get_time(uint8_t time[]);
void update_time(void);
void update_alarm(void);
void alarm(void);
void RTC_IRQHandler(void);
/* Private variables ---------------------------------------------------------*/
char buffer[20];
uint8_t time_now[6] = {0};
uint8_t time_set[6] = {0};
uint8_t i = 0, j = 0;
uint8_t curr_val = 0, prev_val = 0;
/* Private function definitions ----------------------------------------------*/
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM3_Init();
MX_RTC_Init();
OLED_Init();
/* Start the TIM3 timer */
HAL_TIM_Base_Start_IT(&htim3);
/* Infinite loop */
while (1)
{
get_time(time_now); // 获取当前时间
update_time(); // 更新显示时间
update_alarm(); // 更新闹钟时间
curr_val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);
if(curr_val == GPIO_PIN_RESET && prev_val == GPIO_PIN_SET) { // PA1键按下
HAL_Delay(10);
curr_val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);
if(curr_val == GPIO_PIN_RESET) {
i = (i + 1) % 6; // 逐个修改时分秒
time_now[i] = (time_now[i] + 1) % ((i == 0 ? 24 : 60));
}
}
prev_val = curr_val;
curr_val = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2);
if(curr_val == GPIO_PIN_RESET && prev_val == GPIO_PIN_SET) { // PA2键按下
memcpy(time_set, time_now, sizeof(time_set)); // 闹钟时间设为当前时间
}
prev_val = curr_val;
curr_val = HAL_GPIO_ReadPin
该回答引用ChatGPTC
void OLED_Init(void)
{
OLED_WR_Byte(0xAE,OLED_CMD);//--display off
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}
C
static void MX_TIM3_Init(void)
{
htim3.Instance = TIM3;
htim3.Init.Prescaler = 72-1; // 1MHz 的计数频率 (PCLK1 = HCLK / 2 = 72MHz / 2 = 36MHz)
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1000-1; // 1kHz 的计数频率 (时钟周期为 1ms)
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3) {
msTicks++;
if (msTicks>=1000) {
msTicks=0;
seconds++;
if (seconds>=60) {
seconds=0;
minutes++;
if (minutes>=60) {
minutes=0;
hours++;
if (hours>=24) {
hours=0;
}
}
}
}
char buf[20];
sprintf(buf, "Now Time:
%02d:%02d:%02d", hours, minutes, seconds);
OLED_ShowString(0, 0, buf);
}
}
C
/* GPIO Initialization Function */
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA1 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PA2 */
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PA3 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
HAL_NVIC_SetPriority(EXTI2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
HAL_NVIC_SetPriority(EXTI3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
}
C
/* TIM2 init function */
static void MX_TIM2_Init(void)
{
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7200-1; // 每 200ms 扫描一次按键 (PCLK1 = HCLK / 2 = 72MHz / 2 / 7200 = 5kHz)
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 200-1; // 200ms 的计数频率 (时钟周期为 200ms)
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
C
void readButton()
{
if (button1_pressed) {
button1_pressed = 0;
hours = (hours + 1) % 24;
}
if (button2_pressed) {
button2_pressed = 0;
minutes = (minutes + 1) % 60;
}
if (button3_pressed) {
button3_pressed = 0;
alarm_hours = (alarm_hours + 1) % 24;
}
}
C
void checkAlarm()
{
if (hours == alarm_hours && minutes == alarm_minutes && seconds == 0) {
alarm = 1;
for (int i = 0; i < 5; i++) {
OLED_Clear();
OLED_ShowString(25, 2, "Alarm!");
HAL_Delay(1000);
OLED_ShowString(0, 0, "Now Time:
00:00:00");
OLED_ShowString(0, 2, "Set Time:
00:00:00");
HAL_Delay(500);
}
alarm = 0;
}
}
C
#include "main.h"
#include "oled.h"
#include
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
volatile int msTicks = 0;
volatile int seconds = 0;
volatile int minutes = 0;
volatile int hours = 0;
volatile int button1_pressed = 0;
volatile int button2_pressed = 0;
volatile int button3_pressed = 0;
volatile int alarm = 0;
volatile int alarm_hours = 0;
volatile int alarm_minutes = 0;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
static void MX_TIM3_Init(void);
void readButton();
void checkAlarm();
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
MX_TIM3_Init();
OLED_Init();
while (1)
{
readButton();
char buf[20];
sprintf(buf, "Now Time:
%02d:%02d:%02d", hours, minutes, seconds);
OLED_ShowString(0, 0, buf);
sprintf(buf, "Set Time:
%02d:%02d:%02d", alarm_hours, alarm_minutes, 0);
OLED_ShowString(0, 2, buf);
checkAlarm();
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3) {
msTicks++;
if (msTicks>=1000) {
msTicks=0;
seconds++;
if (seconds>=60) {
seconds=0;
minutes++;
if (minutes>=60) {
minutes=0;
hours++;
if (hours>=24) {
hours=0;
}
}
}
}
char buf[20];
sprintf(buf, "Now Time:
%02d:%02d:%02d", hours, minutes, seconds);
OLED_ShowString(0, 0, buf);
}
else if (htim->Instance == TIM2) {
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET) {
button1_pressed = 1;
}
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_RESET) {
button2_pressed = 1;
}
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET) {
button3_pressed = 1;
}
}
}
void readButton()
{
if (button1_pressed && !alarm) {
button1_pressed = 0;
hours = (hours + 1) % 24;
}
if (button2_pressed && !alarm) {
button2_pressed = 0;
minutes = (minutes + 1) % 60;
}
if (button3_pressed) {
button3_pressed = 0;
alarm_hours = (alarm_hours + 1) % 24;
alarm_minutes = (alarm_minutes + 1) % 60;
}
}
void checkAlarm()
{
if (hours == alarm_hours && minutes == alarm_minutes && seconds == 0) {
alarm = 1;
for (int i = 0; i < 5; i++) {
OLED_Clear();
OLED_ShowString(25, 2, "Alarm!");
HAL_Delay(1000);
OLED_ShowString(0, 0, "Now Time:
00:00:00");
OLED_ShowString(0, 2, "Set Time:
00:00:00");
HAL_Delay(500);
}
alarm = 0;
}
}
void SystemClock_Config(void)
{
RCC_OscInit
该回答引用ChatGPTc
// 定义全局变量
uint8_t time[6] = {20, 8, 21, 10, 30, 0}; // 当前时间,初始值为 20:08:21
uint8_t alarm[6] = {20, 8, 21, 10, 31, 0}; // 闹钟时间,初始值为 20:08:31
// 中断服务函数 TIM3
void TIM3_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim3); // 中断处理
uint8_t temp[6];
for (int i = 0; i < 6; i++) {
temp[i] = time[i];
}
// 每秒加 1
time[5]++;
if (time[5] >= 60) {
time[5] = 0;
time[4]++;
}
if (time[4] >= 60) {
time[4] = 0;
time[3]++;
}
if (time[3] >= 24) {
time[3] = 0;
}
if (time[0] == alarm[0] && time[1] == alarm[1] && time[2] == alarm[2] &&
time[3] == alarm[3] && time[4] == alarm[4] && time[5] == alarm[5]) {
// 时间相同,触发闹钟
OLED_Clear();
OLED_ShowString(30, 10, " Alarm!");
OLED_ShowString(20, 30, "Set Time:");
OLED_ShowNum(75, 30, alarm[3], 2, 16);
OLED_ShowString(85, 30, ":");
OLED_ShowNum(95, 30, alarm[4], 2, 16);
OLED_ShowString(105, 30, ":");
OLED_ShowNum(115, 30, alarm[5], 2, 16);
HAL_Delay(1000);
OLED_Clear();
for (int i = 0; i < 6; i++) {
time[i] = temp[i];
}
} else {
// 时间不同,显示当前时间和设置时间
OLED_Clear();
OLED_ShowString(20, 10, "Now Time:");
OLED_ShowNum(75, 10, time[3], 2, 16);
OLED_ShowString(85, 10, ":");
OLED_ShowNum(95, 10, time[4], 2, 16);
OLED_ShowString(105, 10, ":");
OLED_ShowNum(115, 10, time[5], 2, 16);
OLED_ShowString(20, 30, "Set Time:");
OLED_ShowNum(75, 30, alarm[3], 2, 16);
OLED_ShowString(85, 30, ":");
OLED_ShowNum(95, 30, alarm[4], 2, 16);
OLED_ShowString(105, 30, ":");
OLED_ShowNum(115, 30, alarm[5], 2, 16);
HAL_Delay(1000);
}
}
// SysTick 去抖动
void HAL_SYSTICK_Callback(void) {
static uint16_t key1_count = 0;
static uint16_t key2_count = 0;
static uint16_t key3_count = 0;
if (KEY1 == 1 && ++key1_count >= 50) { // 按键1
key1_count = 0;
if (++time[5] >= 60) {
time[5] = 0;
if (++time[4] >= 60) {
time[4] = 0;
if (++time[3] >= 24) {
time[3] = 0;
}
}
}
}
if (KEY2 == 1 && ++key2_count >= 50) { // 按键2
key2_count = 0;
if (++alarm[5] >= 60) {
alarm[5] = 0;
if (++alarm[4] >= 60) {
alarm[4] = 0;
if (++alarm[3] >= 24) {
alarm[3] = 0;
}
}
}
}
if (KEY3 == 1 && ++key3_count >= 50) { // 按键3
key3_count = 0;
// 清零时间和闹钟
time[3] = 0;
time[4] = 0;
time[5] = 0;
alarm[3] = 0;
alarm[4] = 0;
alarm[5] = 0;
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
OLED_Init();
MX_TIM3_Init();
HAL_TIM_Base_Start_IT(&htim3);
SysTick_Config(SystemCoreClock / 100); // 10 毫秒
while (1) {
}
}
c
// 定时器中断服务函数 TIM3
void TIM3_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim3); // 中断处理
static uint16_t count = 0; // 定时器计数器
if (++count >= 1000) { // 1 秒
count = 0;
/* 时间加 1 */
}
}
// SysTick 去抖动
void HAL_SYSTICK_Callback(void) {
static uint16_t key1_count = 0;
static uint16_t key2_count = 0;
static uint16_t key3_count = 0;
if (KEY1 == 1 && ++key1_count >= 50) { // 按键1
key1_count = 0;
// 时间加 1
}
if (KEY2 == 1 && ++key2_count >= 50) { // 按键2
key2_count = 0;
// 设置时间加 1
}
if (KEY3 == 1 && ++key3_count >= 50) { // 按键3
key3_count = 0;
// 清零时间和设置时间
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM3_Init();
HAL_TIM_Base_Start_IT(&htim3);
SysTick_Config(SystemCoreClock / 100); // 10 毫秒
while (1) {
// 循环等待定时器中断和按键中断的触发
}
}
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
由于此问题需要具体代码实现,我将尽可能提供详细的概述和思路,但无法提供完整的代码。
连接和硬件初始化
连接STM32F1实验板和PC,确保J-link仿真器与试验箱CPU板和电脑连接正常。完整连接后,读取并理解原理图,此次试验使用三个按键KEY2、KEY3和KEY4,它们分别接到PA1、PA2和PA3。同时在实验板上,这三个按键标注为KEY1、KEY2、KEY3。在初始化按键之前,需初始化按键时钟,并将IO口配置成上拉输入。
延时和键盘去抖动
建议使用SysTick完成一个10毫秒的延时程序,以完成键盘的扫描。键盘去抖动一般要延时一定的时间,因此在进行按键扫描之前,建议先进行去抖动延时处理。
OLED初始化
在OLED初始化阶段,先完成OLED的IO口配置,然后进行寄存器的配置,并试着在屏幕中显示一个字符以确认通讯的正确。
定时器中断的初始化
定时器内部计数次数最大为2的16次方,因此在此推荐将时钟72分频后计数1000次,从而产生一个1ms的中断。在中断中再计数1000次,获得1s的时间。在此阶段,需要使用通用定时器2或3的初始化,并设置定时器优先级。
实现闹钟功能
利用Proteus实现一个闹钟,闹钟在OLED上显示的时间仅有时分秒,OLED上显示两个时间,上面是两行是运行时间: “Now Time:05:07:00”,下面两行显示闹钟设置时间:“Set Time:05:08:00”。当运行时间等于设定时间时,OLED将显示警告信:“Alarm!”,然后黑屏,再显示上面的提醒信息,如此循环四至五次,时间间隔为1秒,然后继续显示运行时间和设置时间。通过按键更改当前时间和设置闹钟。
以上是实现此闹钟功能的基本思路和步骤。详细的代码实现可以参考相关的STM32F1开发文档和示例代码。
如果我的回答解决了您的问题,请采纳!
针对你的提问,我在我的使用环境中,实现了oled的基本显示,以下是基于Proteus+Keil+STM32CubeMX的oled实验的参考程序,供你参考学习:
main.c中的代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2023 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 "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "oled.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 */
/* 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_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_ShowString(16,0,"Now Time:",16);
OLED_ShowString(14,16,"05:07:00",16);
OLED_ShowString(16,32,"Set Time:",16);
OLED_ShowString(14,48,"05:08:00",16);
OLED_Refresh(); // 刷新屏幕
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 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};
/** 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.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
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_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART2 and Loop until the end of transmission */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* 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 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
实验现象能正常的显示字符:
以下内容部分参考ChatGPT模型:
首先,需要在Keil MDK中创建一个新的STM32CubeMX项目,并进行配置。在配置过程中,需要选择使用通用定时器2或3作为计时器,并配置中断。同时,需要配置GPIO用于连接OLED和按键。
接下来,需要编写代码实现按键扫描、OLED显示和定时器中断。代码示例如下:
#include "stm32f1xx_hal.h"
#include "ssd1306.h"
#define KEY1 GPIO_PIN_0
#define KEY2 GPIO_PIN_1
#define KEY3 GPIO_PIN_2
TIM_HandleTypeDef htim2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
ssd1306_Init();
ssd1306_Fill(Black);
ssd1306_SetCursor(0, 0);
ssd1306_WriteString("Now Time: 00:00:00", Font_11x18, White);
ssd1306_SetCursor(0, 22);
ssd1306_WriteString("Set Time: 00:00:00", Font_11x18, White);
ssd1306_UpdateScreen();
HAL_TIM_Base_Start_IT(&htim2);
while (1)
{
if (HAL_GPIO_ReadPin(GPIOA, KEY1) == GPIO_PIN_RESET)
{
// change current time
}
if (HAL_GPIO_ReadPin(GPIOA, KEY2) == GPIO_PIN_RESET)
{
// change alarm time
}
if (HAL_GPIO_ReadPin(GPIOA, KEY3) == GPIO_PIN_RESET)
{
// clear alarm
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static int cnt = 0;
if (htim->Instance == TIM2)
{
cnt++;
if (cnt >= 1000)
{
cnt = 0;
// update time
ssd1306_SetCursor(0, 0);
ssd1306_WriteString("Now Time: 00:00:00", Font_11x18, White);
ssd1306_SetCursor(0, 22);
ssd1306_WriteString("Set Time: 00:00:00", Font_11x18, White);
ssd1306_UpdateScreen();
// check alarm
}
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
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_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71999;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
需要注意的是,这只是一个示例代码,需要根据具体情况进行修改和完善。
最后,在Proteus中创建一个仿真电路,在其中添加STM32F1教学实验板、OLED和按键,并进行连线。运行仿真即可看到OLED上的显示效果。
如果我的建议对您有帮助、请点击采纳、祝您生活愉快