基于stm32f103c8t6制作一个电子钟。

设计一个电子钟。计时最大值为23:59:59。
要求:(8分)
1、初始值为0:0:0,每秒加1,直到23:59:59,然后清0停止。
2、设计电子钟启动按键,启动后才开始计时;设计清零按键,可随时清0。
3、设计按键调整时间,时分秒均可调整,加法按键:分、秒加到59后清0,时加到23后清0;减法按键:分、秒减到0继续减则为59,时减到0继续减则为23。
4、设计一个初始闹钟时间为0:0:10,可使用串口设置闹钟时间,可响应新设置的闹钟,闹钟时蜂鸣器发声5秒提示。
5、增加光敏电阻,低于阈值发光。

一、仿真设计:

二、初始化:

1、定时器中断计时:配置时钟周期为1s,内部时钟,更新中断

2、外部中断设置:中断少时可忽略优先级设置

3、USART开启:用于闹钟设置

三、代码实现:

1、LCD初始化:chatgpt编写,添加lcd.c库

#include "lcd.h"
LCD_Init();              // 初始化LCD
LCD_Clear();             // 清屏

添加lcd.c文件

#include "gpio.h"
#include "stdio.h"
#define LCD_RS_PIN GPIO_PIN_8
#define LCD_EN_PIN GPIO_PIN_9
#define LCD_D4_PIN GPIO_PIN_4
#define LCD_D5_PIN GPIO_PIN_5
#define LCD_D6_PIN GPIO_PIN_6
#define LCD_D7_PIN GPIO_PIN_7
#define LCD_PORT GPIOB  // 假设LCD接到GPIOB端口
// LCD延时函数
void LCD_Delay(uint32_t delay) {
    HAL_Delay(delay);
}

// 发送4位数据
void LCD_Send4Bit(uint8_t data) {
    HAL_GPIO_WritePin(LCD_PORT, LCD_D4_PIN, (data & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LCD_PORT, LCD_D5_PIN, (data & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LCD_PORT, LCD_D6_PIN, (data & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LCD_PORT, LCD_D7_PIN, (data & 0x08) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    
    // 触发EN
    HAL_GPIO_WritePin(LCD_PORT, LCD_EN_PIN, GPIO_PIN_SET);
    LCD_Delay(1);
    HAL_GPIO_WritePin(LCD_PORT, LCD_EN_PIN, GPIO_PIN_RESET);
    LCD_Delay(1);
}

// 发送命令
void LCD_SendCommand(uint8_t cmd) {
    HAL_GPIO_WritePin(LCD_PORT, LCD_RS_PIN, GPIO_PIN_RESET); // RS = 0 选择命令寄存器
    LCD_Send4Bit(cmd >> 4);   // 发送高4位
    LCD_Send4Bit(cmd & 0x0F); // 发送低4位
}

// 发送数据
void LCD_SendData(uint8_t data) {
    HAL_GPIO_WritePin(LCD_PORT, LCD_RS_PIN, GPIO_PIN_SET); // RS = 1 选择数据寄存器
    LCD_Send4Bit(data >> 4);   // 发送高4位
    LCD_Send4Bit(data & 0x0F); // 发送低4位
}

// LCD初始化函数
void LCD_Init() {
    LCD_Send4Bit(0x03);
    LCD_Send4Bit(0x03);
    LCD_Send4Bit(0x03);
    LCD_Send4Bit(0x02); // 4位模式
    
    LCD_SendCommand(0x28); // 4位模式,2行,5x7点阵
    LCD_SendCommand(0x0C); // 显示开,光标关
    LCD_SendCommand(0x06); // 自动右移
    LCD_SendCommand(0x01); // 清屏
    LCD_Delay(2);
}

// 清屏
void LCD_Clear() {
    LCD_SendCommand(0x01); // 清屏
    LCD_Delay(2);
}

// 设置光标位置
void LCD_SetCursor(uint8_t row, uint8_t col) {
    uint8_t address = (row == 0) ? 0x80 + col : 0xC0 + col;
    LCD_SendCommand(address);
}

// 显示字符串
void LCD_Print(char* str) {
    while (*str) {
        LCD_SendData(*str++);
    }
}

void Display_clock(uint8_t hour,uint8_t minute,uint8_t second) {
    char buffer[16];    
    // 格式化时间为 "HH:MM:SS"
    snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", hour, minute, second);
    
    // 在LCD第一行显示时间
    LCD_SetCursor(0, 3);  // 假设在第一行第4列显示
    LCD_Print(buffer);
}

2、中断回调函数:stm32外部中断后会统一调用下图函数清除标志位,随后进入回调函数,从回调函数中判断中断端口,执行回调函数。(stm32cubemx生成虚函数weak,需用户自行编写)

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN)
{
  if(GPIO_PIN==GPIO_PIN_0)
  {
    increase_hour();
  }
  if(GPIO_PIN==GPIO_PIN_1)
  {
    decrease_hour();
  }
  if(GPIO_PIN==GPIO_PIN_2)
  {
    increase_minute();
  }
  if(GPIO_PIN==GPIO_PIN_3)
  {
    decrease_minute();
  }
  if(GPIO_PIN==GPIO_PIN_4)
  {
    increase_second();
  }
  if(GPIO_PIN==GPIO_PIN_5)
  {
    decrease_second();
  }
	if(GPIO_PIN==GPIO_PIN_7)
	{
		clear();
	}
	if(GPIO_PIN==GPIO_PIN_14)
	{
		reset();
	}
}//外部中断,增加减少时间
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART1) {
        int h, m, s;
        sscanf((char*)rx_buffer, "%2d%2d%2d", &h, &m, &s);
        
        if (h >= 0 && h < 24 && m >= 0 && m < 60 && s >= 0 && s < 60) {
            alarm_hour = h;
            alarm_minute = m;
            alarm_second = s;            
        } 
        HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_buffer, 6);  // 重新启动串口接收
				
    }
}//串口中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim == &htim1)  //判断中断是否来自于定时器1
   {
   	increase_second();
   }

}//定时器中断回调

3、其余代码

volatile uint8_t second = 0, minute = 0, hour = 0,time=0,start=0;
#define LCD_RS_PIN GPIO_PIN_8
#define LCD_EN_PIN GPIO_PIN_9
#define LCD_D4_PIN GPIO_PIN_4
#define LCD_D5_PIN GPIO_PIN_5
#define LCD_D6_PIN GPIO_PIN_6
#define LCD_D7_PIN GPIO_PIN_7
#define LCD_PORT GPIOB  // 假设LCD接到GPIOB端口
volatile uint8_t alarm_hour = 0, alarm_minute = 0, alarm_second = 10;
volatile uint8_t alarm_triggered = 1;
char rx_buffer[8];  // 用于接收串口输入数据

HAL_TIM_Base_Start_IT(&htim1);  
LCD_Init();              // 初始化LCD
LCD_Clear();             // 清屏
HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_buffer, 6); // 串口接收中断
void Check_Alarm();
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);

while (1)//主函数
  {
    Display_clock(hour,minute,second);
    Check_Alarm();
		HAL_ADC_Start(&hadc1);
		adc_value=HAL_ADC_GetValue(&hadc1);
		if(adc_value>100)
		{
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0 , GPIO_PIN_SET);
		}else{
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0 , GPIO_PIN_RESET);
		}
  }
}

void increase_second()//秒增
{
	start=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
  if(time==0&&start==1)
	{
	second++;
  if (second >= 60) 
  {
    second = 0;
    minute++;
    if (minute >= 60) 
    {
      minute = 0;
      hour++;
      if (hour >= 24) 
      {  
			time = 1;
      hour = 0;
      }
    }
  }
  }
}


void decrease_second()//按键功能
{
  second = (second == 0) ? 59 : second - 1; //
}
void increase_hour()
{
  hour = (hour + 1) % 24; //
}
void decrease_hour()
{
  hour = (hour == 0) ? 23 : hour - 1; // 
}
void increase_minute()
{
  minute = (minute + 1) % 60;// 
}
void decrease_minute()
{
  minute = (minute == 0) ? 59 : minute - 1; //
}

void reset()//重启
{
	second=0;hour=0;minute=0;time=0;start=0;
}
void clear()//清零
{
	second=0;hour=0;minute=0;
}

void Check_Alarm(void) //蜂鸣器
{
    if (hour == alarm_hour && minute == alarm_minute && second == alarm_second) 
    {
        alarm_triggered = 1; // 设置闹钟触发标志
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); // 打开蜂鸣?
        //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); // 关闭蜂鸣?
    }
		if((second-alarm_second+60*(minute-alarm_minute))>=5)
		{
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); // 关闭蜂鸣?
		}
}

四、结尾

vscode与keli或者stm32cubemx可能注释文本格式不兼容,generate数次后文本会逐步乱码。若使用六位七段数码管,则利用视觉停留,先输出一位,并延时几毫秒后轮换下一位。

作者:2301_77140380

物联沃分享整理
物联沃-IOTWORD物联网 » stm32电子钟

发表回复