python做网站例子,网站维护中是不是关闭网站了,上网导航网页是哪家公司,沧州市网站建设公司一、前言1.1 关于APM32E030系列APM32E030作为极具性价比的CortexM0系列单片机#xff0c;价格虽然便宜 #xff0c;功能却不少#xff0c;其中就有个带日历功能的RTC。这个RTC可比那些只有个计时器的RTC强太多。拿来做一个电子时钟再好不过了。其中需要显示的年、月、日、星…一、前言1.1 关于APM32E030系列APM32E030作为极具性价比的CortexM0系列单片机价格虽然便宜 功能却不少其中就有个带日历功能的RTC。这个RTC可比那些只有个计时器的RTC强太多。拿来做一个电子时钟再好不过了。其中需要显示的年、月、日、星期、时、分、秒都可以通过寄存器直接读出不需要软件去换算。1.2 电子墨水屏电子墨水屏ePaper是一种采用“微胶囊电泳显示”技术的显示介质通过不同电压吸引不同颜色的墨滴实现黑白或多个颜色的显示由于是显示单元是墨滴所以不需要背光对眼睛比较友好。除了护眼省电也它的一大特色在断电的情况下也能保持显示在刷屏时才费电其他时候可以进入睡眠或者直接断电很适合用来做电子钟或者万年历。手上刚好有之前在海鲜市场上淘的电子标签把上面的2.13寸墨水屏拆下作为显示屏墨水屏的规格如下屏幕型号HINK-E0213A04分辨率 122x250显示颜色黑白支持局部刷新更详细的资料可参考https://www.waveshare.net/wiki/2.13inch_e-Paper_HAT_Manual二、电路部分2.1 APM32E030RBT6和RTC电路主控部分采用APM32E030R Micro-EVB开发板该开发板板载一个 Geehy CMSIS DAPWinUSB调试器据说速度要比HID的那种更快但是在Win7上要手动装一下驱动。RTC相关电路比较简单需要有个32.768KHz的晶振。2.2 电子墨水屏驱动电路电子墨水屏内部电压较高需要一套驱动电路开发板-驱动板-墨水屏这样相连才能驱动墨水屏。做了个驱动板这样开发板就可以通过2.54mm-8P杜邦线与24P的墨水屏接口相连市面上很多墨水屏都是这样的接口这个驱动电路不仅限于这款墨水屏也适用于其他类似的电子墨水屏。三、RTC的程序官方发布的SDK包中有关于RTC的例程这里根据APM32E030_SDK_V1.0.1\Examples\BOARD_APM32E030_TINY\RTC\RTC_Calendar例程进行修改并封装以便于后面的应用程序调用。首先是RTC的初始化主要是配置RTC的时钟并对RTC的参数进行设置。复制voidrtc_init(void){/* RTC Reset */RTC_Init();RTC_Reset();RTC_Init();/* RTC Enable Init */RTC_EnableInit();RTC_ConfigDateStructInit(DateStruct);/* RTC Disable Init */RTC_DisableInit();}为了显示时间和日期需要相关的读取函数复制voidrtc_read_time(unsignedchar*hours,unsignedchar*minutes,unsignedchar*seconds){/* Read time */RTC_ReadTime(RTC_FORMAT_BIN, TimeStruct);RTC_Delay();*hours TimeStruct.hours;*minutes TimeStruct.minutes;*seconds TimeStruct.seconds;}voidrtc_read_data(unsignedchar*year,unsignedchar*month,unsignedchar*day,unsignedchar*weekday){/* Read Date */RTC_ReadDate(RTC_FORMAT_BIN, DateStruct);RTC_Delay();*year DateStruct.year;*month DateStruct.month;*day DateStruct.date;*weekday DateStruct.weekday;}为了设置时间和日期需要相关的写入函数复制voidrtc_write_time(unsignedcharhour,unsignedcharminute,unsignedcharsecond){TimeStruct.H12 12;TimeStruct.hours hour;TimeStruct.minutes minute;TimeStruct.seconds second;RTC_ConfigTime(RTC_FORMAT_BIN, TimeStruct);RTC_Delay();}voidrtc_write_date(unsignedcharyear,unsignedcharmonth,unsignedcharday,unsignedcharweekday){DateStruct.year year;DateStruct.month month;DateStruct.date day;DateStruct.weekday weekday;RTC_ConfigDate(RTC_FORMAT_BIN, DateStruct);RTC_Delay();}因为RTC带有日历功能这部分的程序相对来说简单很多这几个函数已经足够。四、墨水屏的程序4.1 底层硬件驱动电子墨水屏通过SPI接口通信需要用到以下6个信号MOSI - PB5 数据SCK - PB3 时钟CS - PB4 片选DC - PC12 数据/命令控制RST - PB8 复位BUSY - PB9 繁忙检测其中MOSI和SCK可以用硬件SPI的单发送模式来实现也可以用GPIO模拟SPI来实现。底层驱动函数主要包含SPI字节写、写命令、写数据、等繁忙。复制voidepaper_gpio_write_cs(unsignedcharlevel){if(level)GPIO_SetBit(EPAPER_CS_GPIO, EPAPER_CS_PIN);elseGPIO_ClearBit(EPAPER_CS_GPIO, EPAPER_CS_PIN);}voidepaper_gpio_write_rst(unsignedcharlevel){if(level)GPIO_SetBit(EPAPER_RST_GPIO, EPAPER_RST_PIN);elseGPIO_ClearBit(EPAPER_RST_GPIO, EPAPER_RST_PIN);}voidepaper_gpio_write_dc(unsignedcharlevel){if(level)GPIO_SetBit(EPAPER_DC_GPIO, EPAPER_DC_PIN);elseGPIO_ClearBit(EPAPER_DC_GPIO, EPAPER_DC_PIN);}voidepaper_gpio_write_mosi(unsignedcharlevel){if(level)GPIO_SetBit(EPAPER_MOSI_GPIO, EPAPER_MOSI_PIN);elseGPIO_ClearBit(EPAPER_MOSI_GPIO, EPAPER_MOSI_PIN);}voidepaper_gpio_write_sck(unsignedcharlevel){if(level)GPIO_SetBit(EPAPER_SCK_GPIO, EPAPER_SCK_PIN);elseGPIO_ClearBit(EPAPER_SCK_GPIO, EPAPER_SCK_PIN);}unsignedcharepaper_gpio_busy_read(){if(GPIO_ReadInputBit(EPAPER_BUSY_GPIO, EPAPER_BUSY_PIN) BIT_RESET)return0;elsereturn1;}//SPI写字节voidepaper_spi_wrtie(unsignedcharvalue){unsignedchari;__disable_irq();EPAPER_SPI_DELAY;for(i 0; i 8; i){epaper_gpio_write_sck(0);EPAPER_SPI_DELAY;if(value 0x80)epaper_gpio_write_mosi(1);elseepaper_gpio_write_mosi(0);value (value 1);EPAPER_SPI_DELAY;EPAPER_SPI_DELAY1;epaper_gpio_write_sck(1);EPAPER_SPI_DELAY;}__enable_irq();}//写命令voidepaper_write_cmd(unsignedcharcommand){EPAPER_SPI_DELAY;epaper_gpio_write_cs(0);epaper_gpio_write_dc(0);// command writeepaper_spi_wrtie(command);epaper_gpio_write_cs(1);}//写数据voidepaper_write_data(unsignedchardata){EPAPER_SPI_DELAY;epaper_gpio_write_cs(0);epaper_gpio_write_dc(1);// command writeepaper_spi_wrtie(data);epaper_gpio_write_cs(1);}////等待电子纸空闲,超时后会退出unsignedcharepaper_wait_busy(void){unsignedinti 400;while(i--){if(epaper_is_busy() 0)return0;//空闲退出epaper_delay_xms(10);}return-1;//超时退出}4.2 全局刷图片这款屏幕的宽度为122高度为250取模时需要横向取模高位在前。起点坐标和方向如图所示如果想要全屏显示一张图片需要先准备一张122x250分辨率的图片用软件“Image2Lcd”打开这张图片注意选择“水平扫描”取消下方五个选项的勾勾选“颜色翻转”这款屏幕1为白点、0为黑点因此要选择颜色反转。最后点保存 得到一个g_Image.c文件。把g_Image.c中的数组全部写入到到屏幕的内存中去具体步骤先是设置区域大小因为是写入全屏数据所以调用 epaper_driver_set_window(0, 0, 122, 250);在每一行数据写入前设置起点epaper_driver_set_cursor(0, y)然后一次写入整行数据重复多行完成整幅图片的写入。复制//全填充 刷整个屏幕voidepaper_driver_fill(unsignedcharbuffer[]){unsignedshortx, y;unsignedinti 0;epaper_driver_set_window(0,0, EPAPER_WIDTH_PIXEL, EPAPER_HEIGHT_PIXEL);for(y 0; y EPAPER_HEIGHT_PIXEL; y){epaper_driver_set_cursor(0, y);epaper_write_cmd(0x24);for(x 0; x EPAPER_WIDTH_BYTES; x){epaper_write_data(buffer[i]);}}epaper_driver_refresh();}写入到屏幕的SRAM中后屏幕并不会马上刷新还需要发送更新命令。复制//刷新显示voidepaper_driver_refresh(void){epaper_write_cmd(0x22);// DISPLAY_UPDATE_CONTROL_2epaper_write_data(0xC4);epaper_write_cmd(0X20);// MASTER_ACTIVATIONepaper_write_cmd(0xFF);// TERMINATE_FRAME_READ_WRITEepaper_wait_busy();}这样屏幕才会刷新闪烁几次大约3-5秒可完成全屏刷新。涉及的驱动代码很多更详细的代码可以参考上面链接中的微雪示例代码。4.3 局部刷文字局部刷新的方法电子墨水屏全刷耗时较长如果用来显示时间尤其是显示秒数就不太合适这就需要改为局部刷新局部刷新很快不到1秒就可完成。设为局部刷新需要写入一个新的LUT表到屏幕复制//更新LUT, 设置全刷或局刷voidepaper_set_lut_table(unsignedcharmode){epaper_write_cmd(0x32);unsignedshorti;if(mode EPAPER_MODE_FULL)//全刷{for(i 0; i 30; i){epaper_write_data(epaper_lut_full_update[i]);}}elseif(mode EPAPER_MODE_PART)//局刷{for(i 0; i 30; i)epaper_write_data(epaper_lut_partial_update[i]);}else;}自定义字体的制作要想显示日期和时间需要制作相关字库字库就相当于多个字形图片的集合和前面的取模和显示方法类似只不过这里是更小的图片。这里用“PCtoLCD”来制作所需要的字库字幕选项设为”逐行式“选择字体、设置字高、字宽输入想要生成的文字最后点生成字模这样就得到字库数组 const unsigned char DZ_simkai24[]。ASCII字符比较少可以把全部ascii字符做成字库放进MCU中使用也比较简单中文字符太多了全部做成字库放进MCU中不现实所以我选择只把要用到的汉字做成字库其他的字就显示为空格。为了能找到某个汉字字模在这些数组中的位置还需要做个字模和编码的映射关系表。于是先定义这样一个新的数据类型把每个字的GB2312编码和该字模在数组中的位置联系起来。复制typedefstruct{unsignedcharfirst;//GB2312编码unsignedcharsecond;//GB2312编码unsignedintindex;//在字库文件中的索引} FontCode;把所有要用的字的映射关系存放进该结构体数组中复制FontCode DZ_simkai24_code[]{{0x20,0x00,0},// 0200{0xc4,0xea,1},//年c4ea{0xd4,0xc2,2},//月d4c2{0xc8,0xd5,3},//日c8d5{0xd2,0xbb,4},//一d2bb{0xb6,0xfe,5},//二b6fe{0xc8,0xfd,6},//三c8fd{0xcb,0xc4,7},//四cbc4{0xce,0xe5,8},//五cee5{0xc1,0xf9,9},//六c1f9{0xcc,0xec,10},//天ccec{0,0}};后面显示文字时通过检索DZ_simkai24_code中编码可以找到该字在DZ_simkai24[]字模中偏移位置用偏移乘以该字所占大小就能得到数组中的准确位置然后就像画图一样描进画布缓存中。复制//搜索汉字在数组中的索引staticinlineunsignedintepaper_font_search_gb2312(unsignedcharcode[2]){unsignedinti 0;while(curFont.code[i].first 0){if((curFont.code[i].first code[0]) (curFont.code[i].second code[1])){returni;}i;}return0;}//绘制文字voidepaper_draw_text(unsignedshortx0,unsignedshorty0,char*text){unsignedshortx;unsignedintindex;unsignedchar*ptr;unsignedshortfirst;x x0;while(*text !0){if(*text 0x7F)//小于127(0x7F)是ASCII{index epaper_font_search_ascii(*text);ptr curFont.data[index * curFont.size];epaper_clear_windows(x, y0, x curFont.width, y0 curFont.height);if(curPage.area_refresh)epaper_draw_icon_area(x, y0, curFont.width, curFont.height, ptr);elseepaper_draw_icon(x, y0, curFont.width, curFont.height, ptr);x (curFont.width);text;;}else{index epaper_font_search_gb2312(text);ptr curFont.data[index * curFont.size];epaper_clear_windows(x, y0, x curFont.width, y0 curFont.height);if(curPage.area_refresh)epaper_draw_icon_area(x, y0, curFont.width, curFont.height, ptr);elseepaper_draw_icon(x, y0, curFont.width, curFont.height, ptr);x curFont.width;text 2;}}}有了以上代码作为基础显示中文就很简单了复制epaper_font_set(simkai24);epaper_draw_text(0,0, 年 月 日 );为保证能找到正确的文字编码以上代码中的汉字须是GB2312在Keil里面设置一下菜单栏View - Configuration-Editor Encoding 选“Chinese GB1212” 。五、程序整合有了前面的RTC函数和墨水屏显示函数后面实现日期显示和时间显示就容易很多。每隔1秒(或小于1S)读取一次RTC的时间如果时间和上次不同则刷新为当前时间如果时间到了0000:00 则刷新日期代码如下复制//显示实时时间时、分、秒unsignedcharis_refresh_date0;voidgui_page_real_time(){staticunsignedcharold_hour0xff,old_minute0xff,old_second0xff;unsignedcharhour,minute,second;chartemp_str[8];rtc_read_time(hour,minute,second);epaper_font_set(Digiface64);if(hour!old_hour){sprintf(temp_str,%02d,hour);epaper_draw_text(TIME_POS_X,TIME_POS_Y,temp_str);}if(minute!old_minute){sprintf(temp_str,%02d,minute);epaper_draw_text(TIME_POS_X32*3-16,TIME_POS_Y,temp_str);}if(second!old_second){sprintf(temp_str,%02d,second);epaper_draw_text(TIME_POS_X32*6-16,TIME_POS_Y,temp_str);}if((hour!old_hour)||(minute!old_minute)||(second!old_second)){if(curPage.area_refresh0)epaper_driver_fill(curPage.buffer);if(hour0 minute0 second0)is_refresh_date1;}old_hour hour;old_minute minute;old_second second;}//显示实时日期年、月、日voidgui_page_real_date(){staticunsignedcharold_year0xff,old_month0xff,old_day0xff,old_weekday0xff;unsignedcharyear,month,day,weekday;chartemp_str[8];rtc_read_data(year,month,day,weekday);epaper_font_set(Digiface24);if(year!old_year){sprintf(temp_str,20%02d,year);epaper_draw_text(DATE_POS_X,DATE_POS_Y,temp_str);}if(month!old_month){sprintf(temp_str,%02d,month);epaper_draw_text(DATE_POS_X12*6,DATE_POS_Y,temp_str);}if(day!old_day){sprintf(temp_str,%02d,day);epaper_draw_text(DATE_POS_X12*10,DATE_POS_Y,temp_str);}if(weekday!old_weekday){epaper_font_set(simkai24);memcpy(temp_str,WeekdayTab[weekday*2],2);strcat(temp_str,\0);epaper_draw_text(DATE_POS_X12*16,DATE_POS_Y,temp_str);}if((year!old_year)||(month!old_month)||(day!old_day)||(weekday!old_weekday)){if(curPage.area_refresh0)epaper_driver_fill(curPage.buffer);}old_year year;old_month month;old_day day;old_weekdayweekday;}六、测试效果看看最终显示效果---------------------作者shanyuxiang链接https://bbs.21ic.com/icview-3466572-1-1.html来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。