STM32HAL库电子广告牌显示广告+温湿度+时间设置

概述

电子广告牌多用于显示一些简短的信息,像高铁显示行程等数据。在门市上常用于循环显示广告等功能,这次就使用STM32快速开发一个电子广告牌来帮助学长毕业啦!此电子广告牌显示的内容为:
(喜迎23级新生到校->2023年?月?日 当前天气气温?度湿度?%RH-> 恭喜19级学生顺利毕业!->2023年?月?日 当前天气气温?度湿度?%RH)
然后一直循环…

第一天进度

材料采购

元器件number
MAX7219点阵模块¥75.4
STM32F103C8T6最小系统开发板¥14.5
JD3-33蓝牙模块¥6.0
DHT11温湿度传感器¥5.70
硅胶线30AWG¥7.0

这些常用的元器件在某宝上就可以轻松找得到

1.新建KEIL工程

  • 先使用STM32CubeMX配置好基本时钟驱动,引脚驱动。
    在这里插入图片描述
    注意:MAX7219驱动不仅可以使用GPIO直接驱动,还可以使用SPI进行更高的 速率驱动。这里使用哪个都可以。
  • 然后再配置好RTC实时时钟。这里时钟源的配置需要注意一下:
    在这里插入图片描述
    在这里插入图片描述
  • 选择外部晶振可能会不稳定,最终选用内部时钟源驱动。
  • 最后生成KEIL5的工程文件。

2.软件编写

其他模块的驱动就不用多说了。


/**
 * @brief 汉字循环滚动显示
 * @param
 */
void roll_show_hz() {
	char time_buff[3];
    char hour_buf[4];
    char min_nuf[3];
    char sec_buf[2];
    char mon_buf[1];
    char month[1];   //字符串缓存区
    uint8_t times[4] ;
    uint8_t step;
	u8 i = 0;
	int  sx = 64;
	const char buc[] = "123456";
	 char buf[] = "a_b_c_e_f_g_h_i_";    //欢迎新生
	 char buf0[] = "--j_k_l_e_m_n_o_p_q_r_";                        //欢送老生
	u8 temp;
	u8 humidity=0;
	char temp_buf[1];
	char humidity_buf[1];
	u8 buf_temp[] = "z_a-b-c-c-d-";   //当前天气气温
    step = 0;   //显示的步数
	while (1) {
		i++;
		if (i % 20 == 0) {			
			Get_RTC_data(GetData, GetTime);  //获取系统实时时钟	
			temp = leddz_struct.temputure;
			humidity=leddz_struct.humidity;   //获取湿度
			times[0] = GetTime.Hours;
			times[1] = GetTime.Minutes;
			times[2] = GetTime.Seconds;
			if(!GetData.WeekDay){
			times[3] = 7;
			}else{
			times[3]=GetData.WeekDay;
			}
			sprintf(hour_buf, ":%2d:",times[0]);
			sprintf(month, "%d", times[3]);		
			sprintf(min_nuf, "%2d:", times[1]);
			sprintf(sec_buf, "%2d", times[2]);
			if (!step) {
				leddz_clear();
				leddz_show_fonthz_ex(sx, 0, buf);
				leddz_show_reflash();
				sx--;
				if (sx <=-17*8) {
					step = 1;
					sx = 16;
					};
				}
			if (step == 1) {
				leddz_clear();
				char _23  = GetData.Year;
				char date = GetData.Month;
				char day  = GetData.Date;  
				char num0[4], num1[2], num2[2];
				sprintf(num0, "20%d", _23);
				leddz_show_string(sx, 0, num0, 16);
				leddz_show_fonthz_ex(sx + 8 * 4, 0, "s_");         //年
				sprintf(num1, "%d", date);
				leddz_show_string(sx + 8 * 6, 0, num1, 16);
				leddz_show_fonthz_ex(sx + 8 * 7, 0, "t_");          //月
				sprintf(num2, "%d", day);
				leddz_show_string(sx + 8 * 9, 0, num2, 16);
				leddz_show_fonthz_ex(sx + 8 * 11, 0, "u_");         //日		
				leddz_show_reflash();  sx--;
				if (sx <= -13*8) { step = 2;	sx = 64;     
				  };
				}
			if(step==2){
				leddz_clear();
	     	  	leddz_show_fonthz_ex(sx , 0, "z_a-b-c-c-d-");  //当前天气气温
				sprintf(temp_buf, "%d", temp);
				leddz_show_string(sx + 8 * 12, 0, temp_buf, 16);
				leddz_show_fonthz_ex(sx + 8 * 14, 0, "e-");         //度 			
				leddz_show_fonthz_ex(sx+8*16, 0, "s-e-");  //添加湿度汉字
				sprintf(humidity_buf, "%d", humidity);
				leddz_show_string(sx + 8 *20,0, humidity_buf, 16);  
				leddz_show_string(sx + 8 * 22, 0, "%RH", 16);
				//度%RH
        leddz_show_reflash();  sx--;
				if (sx <= -22*8) { step = 3;	sx = 64;     
				  };
			}							
			if (step == 3) {				
				leddz_clear();
			    leddz_show_fonthz_ex(sx, 0, "v_w_");                //时间
				leddz_show_string(sx +   8 *4, 0,   hour_buf, 16);        
				leddz_show_string(sx +  8 * 8, 0,  min_nuf, 16);          
				leddz_show_string(sx + 8 * 11, 0, sec_buf, 16);           
				leddz_show_fonthz_ex(sx + 8 * 13, 0, "x_y_");       //星期                            
				leddz_show_string(sx + 8 * 17, 0, month, 16);
				leddz_show_reflash();
                 sx--;         
				if (sx <= -20*8) {        
					step = 4;              
					sx = 64;           
					};         
				}        				
			if (step == 4) {
				leddz_clear();
				leddz_show_fonthz_ex(sx, 0, buf0);    //恭喜顺利毕业
				leddz_show_reflash();
				sx--;
				if (sx <= -23*8) {
					step = 5;
					sx = 64;
					};
				}
			if (step == 5) {
				leddz_clear();
				char _23  = GetData.Year;
				char date = GetData.Month;
				char day  = GetData.Date;  
				char num0[4], num1[2], num2[2];
				sprintf(num0, "20%d", _23);
				leddz_show_string(sx, 0, num0, 16);
				leddz_show_fonthz_ex(sx + 8 * 4, 0, "s_");         //年
				sprintf(num1, "%d", date);
				leddz_show_string(sx + 8 * 6, 0, num1, 16);
				leddz_show_fonthz_ex(sx + 8 * 7, 0, "t_");          //月
				sprintf(num2, "%d", day);
				leddz_show_string(sx + 8 * 9, 0, num2, 16);
				leddz_show_fonthz_ex(sx + 8 * 11, 0, "u_");         //日				
				leddz_show_reflash();
				sx--;
				if (sx <= -13*8) {
					step =6;
					sx = 64;
					};			
				}
			if(step==6){
				leddz_clear();
		     	leddz_show_fonthz_ex(sx , 0, "z_a-b-c-c-d-");  //当前天气气温
				sprintf(temp_buf, "%d", temp);
				leddz_show_string(sx + 8 * 12, 0, temp_buf, 16);
				leddz_show_fonthz_ex(sx + 8 * 14, 0, "e-");         //度 				
				leddz_show_fonthz_ex(sx+8*16, 0, "s-e-");  //添加湿度汉字
				sprintf(humidity_buf, "%d", humidity);
				leddz_show_string(sx + 8 *20,0, humidity_buf, 16);  
				leddz_show_string(sx + 8 * 22, 0, "%RH", 16);
				//度%RH
               leddz_show_reflash();  sx--;
				if (sx <= -22*8) { step = 7;	sx = 64;     
				  };
			}			
				if(step==7){
				leddz_clear();
				leddz_show_fonthz_ex(sx, 0, "v_w_");     //时间
				leddz_show_string(sx + 8 *4, 0, hour_buf, 16);
				leddz_show_string(sx + 8 * 8, 0, min_nuf, 16);
				leddz_show_string(sx + 8 * 11, 0, sec_buf, 16);
				leddz_show_fonthz_ex(sx + 8 * 13, 0, "x_y_");     //星期
				leddz_show_string(sx + 8 * 17, 0, month, 16);
				leddz_show_reflash(); sx--;
				if (sx <= -18*8) {
					step = 0;
					sx = 64;
					};	
				}
	    i = 0;
			HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
			}
		delay_ms(1);
		}
	}
  • 程序很简单,就是堆上去的!
  • 时间的的更改,为了保证当前的时间是准确的,肯定要能够调节时间,不然每次上一次程序断电后就不准了!
    之前元器件采用到了蓝牙模块,那就派上了用场了。直接接收手机端蓝牙调试器发送过来的数据进行读取,然后就能够调节时间了!
    串口就配置成正常的异步通讯就行,我这里采用了DMA接收。

/**
 * @brief 串口重定向打印数据
 * @param ch
 * @param f
 * @return
 */
int fputc(int ch, FILE* f) {
	HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 0xffff);
	return ch;
	}

RTC_DateTypeDef SetData;   //设置日期结构体
RTC_TimeTypeDef SetTime;   //设置时间结构体
uint8_t buff[12];
char Data_data[14];
//  DMA加串口空闲中断
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == USART1)
	{
		static uint8_t i=0;
		char buff_data[1];
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1,buff,sizeof(buff));//因为是normal模式再次开启DMA的空闲中断接受
		sprintf(buff_data,"%c",buff[0]);
        Data_data[i++]=atoi(buff_data);	
		if(buff[0]==0x72){
		  i=0;
	    for(uint8_t j=0;j<sizeof(Data_data);j++){
			Data_data[j]=0;
			}
		}
        SetData.Year=Data_data[0]*1000+Data_data[1]*100+Data_data[2]*10+Data_data[3];
		SetData.Month=Data_data[4]*10+Data_data[5];
		SetData.Date=Data_data[6]*10+Data_data[7];
        SetTime.Hours=Data_data[8]*10+Data_data[9];
		SetTime.Minutes=Data_data[10]*10+Data_data[11];
		SetTime.Seconds=Data_data[12]*10+Data_data[13];
		if(i>sizeof(Data_data)-1){
			Set_RTC_data(&SetData,&SetTime);
			printf("setting sucessfully!");
			step=0;
		i=0;
		}
	}
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1,buff,sizeof(buff)); //串口1开启DMA接受
}

  • 通信协议的话直接采用例子:20200402122156 就是2020年4月2日12点21分56秒 stm32 会自动计算出星期几。

  • R就是复位按键
    在这里插入图片描述

  • 注意这里采用了atoi()函数将字符串转换为变量的值。由于手机端的串口调试器是将变量转换为字符串进行发送的。

  • 到这里第一天的的进度就差不多了。

第二天进度

1.开始接线

  • 刚好等到材料都到齐了,开始接线。
    MAX7219一共有五个引脚
    在这里插入图片描述
引脚名称功能
Vcc电源正极(5V)
GND电源地
DIN数据输入端
CS片选信号端(拉低使能)
CLK时钟信号
  • 这三根信号线可以直接使用SPI来驱动
  • 把这些线依次与STM32 配置的引脚相对应接好就行了。

2.开始调试

  • 先检查每根线的波形是不是正确的,可以使用示波器观察。

在这里插入图片描述

  • 然后接上MAX7219调试细节部分。
    在这里插入图片描述

总结

  • 此次意外接到的毕设让我在慌乱中抽出一点时间来完成,也祝愿学长顺利毕业吧!
  • 后续我将编写、制作更多的小制作供大家共同学习进步,前行路上欢迎一键三连,感谢各位大佬!
  • 最后附上源码工程:
  • 百度网盘: https://pan.baidu.com/s/1J1Btn-NyuARS4HNFKl8TZQY
  • 链接: ntl2
  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值