Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread学习营
英飞凌Infineon
夏令营
RTT夏令营实践作业——基于Psoc6开发板设计的OLED时钟
发布于 2023-07-27 20:32:24 浏览:336
订阅该版
[tocm] # 设计背景 我组大部分成员皆是初次接触嵌入式开发系统,因此根据本次夏令营学习及导师推荐下我们选择了设计难度较低的OLED时钟设计。在导师的帮助下完成了整个工程的搭建。 # 设计思路 采用市面上比较常见的SSD1306显示屏作为时钟的载体。设计的思路是: - 1.使用本次夏令营下发的Psoc6-evaluationkit-062S2开发板驱动OLED屏 - 2.使用RT-THREAD Studio设置RTC获取时间 - 3.将时间显示在OLED屏上并设计简单的数字滚动功能 # 开发工具 - 1.Psoc6-evaluationkit-062S2开发板 - 2.RT-THREAD Studio - 3.SSD1306四排真OLED屏 #开发成果展示 ![screenshot_图片.png](https://oss-club.rt-thread.org/uploads/20230727/b368ba15fee3c1e2c28840f5730fd78a.png.webp) 附有视频文件 [OLED.mp4](https://club.rt-thread.org/file_download/dd7ce388c120c34d) # RT-THREAD Studio软件包设置 其中参考了SSD1306软件包及RTC例程因此SSD1306软件包需单独下载 ![screenshot_图片.png](https://oss-club.rt-thread.org/uploads/20230727/20c92974097c01ae10a0b724ca3c60ae.png.webp) ![screenshot_图片.png](https://oss-club.rt-thread.org/uploads/20230727/e27cd7d262997ce79048aa34b532ae7d.png.webp) ![screenshot_图片.png](https://oss-club.rt-thread.org/uploads/20230727/e6755f6a4870345ce958de793930e829.png.webp) # 开发心得 作为初次接触嵌入式操作系统的初学者,学习中有些许困难。主要在于不能清楚的掌握模块的调用,初次接触线程的概念、使用经过rtt封装过的C语言头文件及rtt中的基本函数。在大致读懂后明白了rtt已经将许多模块写好可以直接调用,各位前辈的软件包是的开发更具模块化。裸机开发与嵌入式操作系统开发的区别很大但EOS的简洁明了显而易见,不过代码的移植也是入门的难点之一。 # 参考资料 - 1.CW32L052 体验丝滑数字OLED小时钟[https://bbs.21ic.com/icview-3315978-1-1.html](https://bbs.21ic.com/icview-3315978-1-1.html) - 2.SSD1306软件包 - 3.RTC使用例程 **下附完整的工程代码** # 工程代码 1.OLED屏驱动 ```c #include "oled.h" #include
#include
#include "codetab.h" //oled显示尺寸 uint16_t const displayWidth = 128; uint16_t const displayHeight = 64; /* OLED显存 [0]0 1 2 3 ... 127 [1]0 1 2 3 ... 127 [2]0 1 2 3 ... 127 [3]0 1 2 3 ... 127 [4]0 1 2 3 ... 127 [5]0 1 2 3 ... 127 [6]0 1 2 3 ... 127 [7]0 1 2 3 ... 127 */ static uint8_t OLED_RAM[8][128];//定义GDDRAM缓存区 #define CW_OLED_I2C CW_I2C1 #define OLED_ADDR 0x3c #define SSD1306_CTRL_CMD 0x00 #define SSD1306_CTRL_DATA 0x40 #define SSD1306_MASK_CONT (0x1<<7) static struct rt_i2c_bus_device *i2c_bus; void OLED_I2C_Init(void) { i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(PKG_USING_SSD1306_I2C_BUS_NAME); if (i2c_bus == RT_NULL) { rt_kprintf("can not find %s device", PKG_USING_SSD1306_I2C_BUS_NAME); return; } } //向OLED寄存器地址写一个byte的数据 //int I2C_WriteByte(uint8_t addr,uint8_t data) //{ // // return 0; //} /************************************************************** Prototype : void WriteCmd(uint8_t IIC_Command) Parameters : IIC_Command return : none Description : 写命令 ***************************************************************/ void WriteCmd(uint8_t IIC_Command) { // I2C_WriteByte(0x00, IIC_Command); uint8_t buf[2] = {SSD1306_CTRL_CMD, IIC_Command}; rt_i2c_master_send(i2c_bus, OLED_ADDR, RT_I2C_WR, buf, 2); } /************************************************************** Prototype : void WriteDat(uint8_t IIC_Data) Parameters : IIC_Data return : none Description : 写数据 ***************************************************************/ void WriteDat(uint8_t IIC_Data) { //I2C_WriteByte(0x40, IIC_Data); uint8_t buf[2] = {SSD1306_CTRL_DATA, IIC_Data}; rt_i2c_master_send(i2c_bus, OLED_ADDR, RT_I2C_WR, buf, 2); } /************************************************************** Prototype : void OLED_Init(void) Parameters : none return : none Description : 初始化OLED模块 ***************************************************************/ void OLED_Init(void) { OLED_I2C_Init(); rt_thread_mdelay(500); WriteCmd(0xAE); //开显示 WriteCmd(0x20); //设置内存寻址模式 WriteCmd(0x00); //00,水平寻址模式;01,垂直寻址模式;10,页面寻址模式(重置);11,无效 WriteCmd(0x21); //设置列开始和结束地址 WriteCmd(0x00); //列起始地址,范围:0 – 127d (默认值 = 0d) WriteCmd(0x7F); //列结束地址,范围:0 – 127d (默认值 = 127d) WriteCmd(0x22); //页面设置开始和结束地址 WriteCmd(0x00); //页面起始地址,范围:0-7d (默认值= 0d) WriteCmd(0x07); //页面结束地址,范围:0-7d (默认值= 7d) WriteCmd(0xc8); //设置COM输出扫描方向 WriteCmd(0x40); //--设置起始行地址 WriteCmd(0x81); //--set contrast control register WriteCmd(0xff); //亮度调节 0x00~0xff WriteCmd(0xa1); //--设置段重新映射0到127 WriteCmd(0xa6); //--设置正常显示 WriteCmd(0xa8); //--设置复用比(1 ~ 64) WriteCmd(0x3F); // WriteCmd(0xa4); //0xa4,输出遵循RAM内容;0xa5,Output忽略RAM内容 WriteCmd(0xd3); //-设置显示抵消 WriteCmd(0x00); //-not offset WriteCmd(0xd5); //--设置显示时钟分频/振荡器频率 WriteCmd(0xf0); //--设置分率 WriteCmd(0xd9); //--设置pre-charge时期 WriteCmd(0x22); // WriteCmd(0xda); //--设置com大头针硬件配置 WriteCmd(0x12); WriteCmd(0xdb); //--设置vcomh WriteCmd(0x20); //0x20,0.77xVcc WriteCmd(0x8d); //--设置DC-DC WriteCmd(0x14); // WriteCmd(0xaf); //--打开oled面板 OLED_FullyClear();//清屏 } /************************************************************** Prototype : void OLED_ON(void) Parameters : none return : none Description : 将OLED从休眠中唤醒 ***************************************************************/ void OLED_ON(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X14); //开启电荷泵 WriteCmd(0XAF); //OLED唤醒 } /************************************************************** Prototype : void OLED_OFF(void) Parameters : none return : none Description : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA ***************************************************************/ void OLED_OFF(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X10); //关闭电荷泵 WriteCmd(0XAE); //OLED休眠 } /************************************************************** Prototype : void OLED_RefreshRAM(void) Parameters : none return : none Description : 全屏填充 ***************************************************************/ void OLED_RefreshRAM(void) { for(uint16_t m = 0; m < displayHeight/8; m++) { for(uint16_t n = 0; n < displayWidth; n++) { WriteDat(OLED_RAM[m][n]); } } } /************************************************************** Prototype : void OLED_RefreshRAM_Test(void) Parameters : Page_Start 页开始地址(最小为0) Parameters : Page_Stop 页结束地址(最大为7) Parameters : Column_Start 列开始地址(最小为0) Parameters : Column_Stop 列结束地址(最大为127) return : none Description : 区域填充 ***************************************************************/ void OLED_RefreshPartRAM(uint8_t Page_Start, uint8_t Page_Stop, uint8_t Column_Start, uint8_t Column_Stop) { WriteCmd(0X21); //设置列地址 WriteCmd(Column_Start); //列开始地址 WriteCmd(Column_Stop); //列结束地址 WriteCmd(0X22); //设置页地址 WriteCmd(Page_Start); //页开始地址 WriteCmd(Page_Stop); //页结束地址 for(uint16_t m = Page_Start; m < (Page_Stop + 1); m++) { for(uint16_t n = Column_Start; n < (Column_Stop + 1); n++) { WriteDat(OLED_RAM[m][n]); } } } /************************************************************** Prototype : void OLED_ClearRAM(void) Parameters : none return : none Description : 清除数据缓冲区 ***************************************************************/ void OLED_ClearRAM(void) { for(uint16_t m = 0; m < displayHeight/8; m++) { for(uint16_t n = 0; n < displayWidth; n++) { OLED_RAM[m][n] = 0x00; } } } /************************************************************** Prototype : void OLED_Fill(uint8_t fill_Data) Parameters : fill_Data 填充的1字节数据 return : none Description : 全屏填充 0x00~0xff ***************************************************************/ void OLED_FullyFill(uint8_t fill_Data) { for(uint16_t m = 0; m < displayHeight/8; m++) { for(uint16_t n = 0; n < displayWidth; n++) { OLED_RAM[m][n] = fill_Data; } } OLED_RefreshRAM(); } /************************************************************** Prototype : void OLED_FullyClear(void) Parameters : none return : none Description : 全屏清除 ***************************************************************/ void OLED_FullyClear(void) { OLED_FullyFill(RESET_PIXEL); } /************************************************************** Prototype : void OLED_SetPixel(int16_t x, int16_t y, uint8_t set_pixel) Parameters : x,y -- 起始点坐标(x:0~127, y:0~63); set_pixel 该点的数据 SET_PIXEL = 1, RESET_PIXEL = 0 return : none Description : 设置坐标像素点数据 ***************************************************************/ void OLED_SetPixel(int16_t x, int16_t y, uint8_t set_pixel) { if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) { if(set_pixel){ OLED_RAM[y/8][x] |= (0x01 << (y%8)); } else{ OLED_RAM[y/8][x] &= ~(0x01 << (y%8)); } } } /************************************************************** Prototype : void OLED_GetPixel(int16_t x, int16_t y) Parameters : x,y -- 起始点坐标(x:0~127, y:0~63); return : PixelStatus 像素点状态 SET_PIXEL = 1, RESET_PIXEL = 0 Description : 获得坐标像素点数据 ***************************************************************/ PixelStatus OLED_GetPixel(int16_t x, int16_t y) { if(OLED_RAM[y/8][x] >> (y%8) & 0x01) return SET_PIXEL; return RESET_PIXEL; } /************************************************************** Prototype : void OLED_ShowStr(int16_t x, int16_t y, uint8_t ch[], uint8_t TextSize) Parameters : x,y -- 起始点坐标(x:0~127, y:0~63); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16) return : none Description : 显示codetab.h中的ASCII字符,有6*8和8*16可选择 ***************************************************************/ void OLED_ShowStr(int16_t x, int16_t y, uint8_t ch[], uint8_t TextSize) { if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) { int32_t c = 0; uint8_t j = 0; switch(TextSize) { case 1: { while(ch[j] != '\0') { c = ch[j] - 32; if(c < 0) //无效字符 break; if(x >= 125 || (127-x < 6))//一行最大显示字符数:21字节显示,多出两列,不显示 || 剩余列小于6不能显示完整字符,换行显示 { x = 0; y += 8;//换行显示 if(63 - y < 8) // 不足以显示一行时不显示 break; } for(uint8_t m = 0; m < 6; m++) { for(uint8_t n = 0; n < 8; n++) { OLED_SetPixel(x+m, y+n, (F6x8[c][m] >> n) & 0x01); } } x += 6; j++; } }break; case 2: { while(ch[j] != '\0') { c = ch[j] - 32; if(c < 0) //无效字符 break; if(x >= 127 || (127-x < 8))//16字节显示 || 剩余列小于8不能显示完整字符,换行显示 { x = 0; y += 16;//换行显示 if(63 - y < 16) // 不足以显示一行时不显示 break; } for(uint8_t m = 0; m < 2; m++) { for(uint8_t n = 0; n < 8; n++) { for(uint8_t i = 0; i < 8; i++) { OLED_SetPixel(x+n, y+i+m*8, (F8X16[c][n+m*8] >> i) & 0x01); } } } x += 8; j++; } }break; } } } /************************************************************** Prototype : void OLED_ShowCN(int16_t x, int16_t y, uint8_t* ch) Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); CN[]:汉字在codetab.h中的索引 return : none Description : 显示codetab.h中的汉字,16*16点阵 ***************************************************************/ void OLED_ShowCN(int16_t x, int16_t y, uint8_t* ch) { if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) { int32_t len = 0; while(ch[len] != '\0') { if(x >= 127 || (127-x < 16))//8个汉字显示||剩余列小于16不能显示完整字符,换行显示 { x = 0; y += 16; if(63 - y < 16) // 不足以显示一行时不显示 break; } //需要处理输入数据大于显示数据的问题 for(uint8_t i = 0; i < sizeof(F16x16_CN)/sizeof(GB2312_CN); i++) { if(((F16x16_CN[i].index[0] == ch[len]) && (F16x16_CN[i].index[1] == ch[len+1]))){ for(uint8_t m = 0; m < 2; m++) //页 { for(uint8_t n = 0; n < 16; n++) // 列 { for(uint8_t j = 0; j < 8; j++) // 行 { OLED_SetPixel(x+n, y+j+m*8, (F16x16_CN[i].encoder[n+m*16] >> j) & 0x01); } } } x += 16; len += 2; break; } else if(F16x16_CN[i].index[0] == ch[len] && ch[len] == 0x20){ for(uint8_t m = 0; m < 2; m++) { for(uint8_t n = 0; n < 16; n++) { for(uint8_t j = 0; j < 8; j++) { OLED_SetPixel(x+n, y+j+m*8, (F16x16_CN[i].encoder[n+m*16] >> j) & 0x01); } } } x += 16; len++; break; } } } } } /************************************************************** Prototype : void OLED_Show_MixedCH(int16_t x, int16_t y, uint8_t* ch) Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); CN[]:汉字在codetab.h中的索引 return : none Description : 显示codetab.h中的汉字,16*16点阵,英文,8*16点阵 ***************************************************************/ void OLED_ShowMixedCH(int16_t x, int16_t y, uint8_t* ch) { if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) { int32_t len = 0, c; while(ch[len] != '\0') { if(ch[len] >= 0xa1)//GB2312从0xA1A0开始 { for(uint8_t i = 0; i < sizeof(F16x16_CN)/sizeof(GB2312_CN); i++) { if(((F16x16_CN[i].index[0] == ch[len]) && (F16x16_CN[i].index[1] == ch[len+1]))) { if(x >= 127|| (127-x < 16))//8个汉字显示||剩余列小于16不能显示完整字符,换行显示 { x = 0; y += 16; if(63 - y < 16) // 不足以显示一行时不显示 break; } for(uint8_t m = 0; m < 2; m++) //页 { for(uint8_t n = 0; n < 16; n++) //列 { for(uint8_t j = 0; j < 8; j++) //行 { OLED_SetPixel(x+n, y+j+m*8, (F16x16_CN[i].encoder[n+m*16] >> j) & 0x01); } } } x += 16; len += 2; break; } } } else if(ch[len] <= 127)//ASCII编码范围0-127 { c = ch[len] - 32; if(c < 0) // 无效字符 break; if(x >= 127 || (127-x < 8))//16字节显示 || 剩余列小于8不能显示完整字符,换行显示 { x = 0; y += 16; if(63 - y < 16) // 不足以显示一行时不显示 break; } for(uint8_t m = 0; m < 2; m++) { for(uint8_t n = 0; n < 8; n++) { for(uint8_t i = 0; i < 8; i++) { OLED_SetPixel(x+n, y+i+m*8, (F8X16[c][n+m*8] >> i) & 0x01); } } } x += 8; len++; } } } } /*************************************************************** Prototype : void OLED_DrawBMP(int16_t x0,int16_t y0,int16_t L,int16_t H,const uint8_t BMP[]) Parameters : (x0,y0)坐标长L宽H区域绘制图像BMP 0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序 return : none Description : 区域图像绘制,显示BMP位图,格式使用二维数组存储 ***************************************************************/ void OLED_DrawBMP(int16_t x0,int16_t y0,int16_t L,int16_t H,const uint8_t BMP[]) { if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\ y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) { uint8_t *p = (uint8_t *)BMP; for(int16_t y = y0; y < y0+H; y+=8) { for(int16_t x = x0; x < x0+L; x++) { for(int16_t i = 0; i < 8; i++) { // OLED_SetPixel(x, y+i, ((*((uint8_t *)BMP+(x-x0)+L*((y-y0)/8))) >> i) & 0x01); OLED_SetPixel(x, y+i, ((*p) >> i) & 0x01); } p++; } } } } /*************************************************************** Prototype : void OLED_AreaFill(int16_t x0,int16_t y0,int16_t L,int16_t H) Parameters : 区域内容清除,(x0,y0)坐标长L宽H区域 0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序 return : none Description : 规定区域内容填充 ***************************************************************/ void OLED_AreaFill(int16_t x0,int16_t y0,int16_t L,int16_t H, uint8_t fill_data) { if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\ y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) { for(int16_t y = y0; y < y0+H; y++) { for(int16_t x = x0; x < x0+L; x++) { for(int16_t i = 0; i < 8; i++) { OLED_SetPixel(x, y+i, (fill_data >> i) & SET_PIXEL); } } } OLED_RefreshRAM(); } } /*************************************************************** Prototype : void OLED_AreaCLR(int16_t x0,int16_t y0,int16_t L,int16_t H) Parameters : (x0,y0)坐标长L宽H区域 0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序 return : none Description : 规定区域内容清除 ***************************************************************/ void OLED_AreaClear(int16_t x0,int16_t y0,int16_t L,int16_t H) { if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\ y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) { for(int16_t y = y0; y < y0+H; y+=8) { for(int16_t x = x0; x < x0+L; x++) { for(int16_t i = 0; i < 8; i++) { OLED_SetPixel(x, y+i, RESET_PIXEL); } } } //OLED_RefreshRAM(); } } /*************************************************************** Prototype : void OLED_FullyToggle(void) Parameters : none return : none Description : 缓冲区数据取反后刷新到GDDRAM ***************************************************************/ void OLED_FullyToggle(void) { for(uint16_t m = 0; m < displayHeight/8; m++) { for(uint16_t n = 0; n < displayWidth; n++) { OLED_RAM[m][n] = ~OLED_RAM[m][n]; } } OLED_RefreshRAM(); } /*************************************************************** Prototype : void OLED_AreaToggle(int16_t x0,int16_t y0,int16_t L,int16_t H) Parameters : (x0,y0)坐标长L宽H区域 0<=x0<=127 0<=y0<=63 0<=L+x0<=127 0<=H+y0<= 63 图像取模 纵向取模,字节倒序 return : none Description : 规定区域内容取反 ***************************************************************/ void OLED_AreaToggle(int16_t x0,int16_t y0,int16_t L,int16_t H) { if (x0 >= 0 && x0 < displayWidth && x0+L <= displayWidth &&\ y0 >= 0 && y0 < displayHeight && y0+H <= displayHeight) { for(int16_t y = y0; y < y0+H; y+=8) { for(int16_t x = x0; x < x0+L; x++) { for(int16_t i = 0; i < 8; i++) { OLED_SetPixel(x, y+i, !OLED_GetPixel(x, y+i)); } } } OLED_RefreshRAM(); } } /**************************************************************** 全屏垂直偏移,0->63方向 方向垂直向上,范围0-63 方向垂直向下,范围63-0 ****************************************************************/ void OLED_VerticalShift(void) { for(uint8_t i = 0; i < displayHeight; i++) { WriteCmd(0xd3);//设置显示偏移,0->63方向 WriteCmd(i);//偏移量 rt_thread_mdelay(40);//延时时间 } } /**************************************************************** 屏幕内容水平全屏滚动播放 左 LEFT 0x27 右 RIGHT 0x26 ****************************************************************/ void OLED_HorizontalShift(uint8_t direction) { WriteCmd(direction);//设置滚动方向 WriteCmd(0x00);//虚拟字节设置,默认为0x00 WriteCmd(0x00);//设置开始页地址 WriteCmd(0x05);//设置每个滚动步骤之间的时间间隔的帧频 WriteCmd(0x07);//设置结束页地址 WriteCmd(0x00);//虚拟字节设置,默认为0x00 WriteCmd(0xff);//虚拟字节设置,默认为0xff WriteCmd(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据 } /**************************************************************** 屏幕内容垂直水平全屏滚动播放 上 UP 0x29 下 DOWN 0x2A ****************************************************************/ void OLED_VerticalAndHorizontalShift(uint8_t direction) { WriteCmd(direction);//设置滚动方向 WriteCmd(0x00);//虚拟字节设置,默认为0x00 WriteCmd(0x00);//设置开始页地址 WriteCmd(0x05);//设置每个滚动步骤之间的时间间隔的帧频 WriteCmd(0x07);//设置结束页地址 WriteCmd(0x01);//垂直滚动偏移量 WriteCmd(0x2f);//开启滚动-0x2f,禁用滚动-0x2e,禁用需要重写数据 } /**************************************************************** 屏幕内容取反显示 开 ON 0xA7 关 OFF 0xA6 默认此模式,设置像素点亮 ****************************************************************/ void OLED_DisplayMode(uint8_t mode) { WriteCmd(mode); } /**************************************************************** 屏幕亮度调节 intensity 0-255 默认为0x7f ****************************************************************/ void OLED_IntensityControl(uint8_t intensity) { WriteCmd(0x81); WriteCmd(intensity); } /*************************************************************** Prototype : uint8_t GetPixel_For_Scroll(int16_t x, int16_t y, const uint8_t BMP[], uint8_t W) Parameters : x 横坐标 Parameters : y 纵坐标 Parameters : BMP[] bmp图片(二维数组) Parameters : W bmp图片宽度(像素) return : 坐标点数据 Description : 获得坐标像素点数据(可以为滚动动画服务) ***************************************************************/ uint8_t GetPixel_For_Scroll(int16_t x, int16_t y, const uint8_t BMP[], uint8_t W) { uint8_t *p = (uint8_t *)BMP; p += x + (y/8)*W; if((*p) >> (y%8) & 0x01) return 1; return 0; } /*************************************************************** Prototype : void SetPixel_for_ScrollDigit(int16_t X, int16_t Y, int16_t x, int16_t y, uint8_t set_pixel) Parameters : X Parameters : Y Parameters : x Parameters : y Parameters : set_pixel return : none Description : 设置坐标像素点数据(可以为滚动动画服务) ***************************************************************/ void SetPixel_For_Scroll(int16_t X, int16_t Y, int16_t x, int16_t y, uint8_t set_pixel) { if(set_pixel) { OLED_RAM[(Y+y)/8][X+x] |= (0x01 << ((Y+y)%8)); } else { OLED_RAM[(Y+y)/8][X+x] &= ~(0x01 << ((Y+y)%8)); } } /**************************************************************************************************************************************************** Prototype : void Draw_Digit_BMP(uint16_t x1, uint16_t y1, const uint8_t BMP[], uint16_t Y,uint8_t W, uint8_t H, uint16_t end_line) Parameters : x1 确定图片显示位置(左上角像素点横坐标) Parameters : y1 确定图片显示位置(左上角像素点纵坐标) Parameters : BMP[] 素材图片 Parameters : Y 所选的一帧图片在素材图片中的纵坐标 Parameters : W 素材图片宽度(也是一帧图片的宽度) Parameters : H 一帧图片的高度 Parameters : end_line 在素材图片中划出最后一行(用于滚动循环,首尾相接) return : none Description : 从bmp大图片中获取小图片作为滚动动画的一帧图片 *****************************************************************************************************************************************************/ void Draw_BMP_For_Scroll(uint16_t x1, uint16_t y1, const uint8_t BMP[], uint16_t Y, uint8_t W, uint8_t H, uint16_t end_line) { uint16_t x0,y0,y,Temp; for(y = Y , y0 = 0 ; y0 < H ; y++ , y0++) { if(y > end_line) y -= (end_line+1); for(x0 = 0; x0 < W ; x0++) { Temp = GetPixel_For_Scroll(x0, y, BMP, W); SetPixel_For_Scroll(x1,y1,x0,y0,Temp); } } } ``` 2.屏幕数字滚动 ```c #include
uint8_t Hour=0,Minute=59,Second=55;//时间参数 uint8_t H1,H2,M1,M2,S1,S2;//时钟时分秒六位数字 static uint16_t Y1=0,Y2=0,Y3=0,Y4=0,Y5=0,Y6=0; static uint8_t TEMP; void Draw_Rolling_Clock() { switch(H1) { case 0:if(Y1 < 24*2+1) Y1 = 24*2;if(Y1 < 24*2+24) Y1++;break; case 1: case 2:if(Y1 < H1*24-23 || Y1 > H1*24) Y1 = H1*24-24;if(Y1 < H1*24) Y1++; } Draw_BMP_For_Scroll(0, 16, Scroll_Digit_BMP[0], Y1, 20, 24, 2*24+23);//end_line=2*24+23,Scroll_Digit_Small_BMP划到2*24+23行,即0~2 switch(H2) { case 0: { if(Hour == 0) {TEMP = 3;if(Y2 < 24*3+1 || Y2 > 4*24) Y2 = 24*3;if(Y2 < 24*3+24) Y2++;break;} if(Hour == 10 || Hour == 20){TEMP = 9;if(Y2 < 24*9+1) Y2 = 24*9;if(Y2 < 24*9+24) Y2++;break;} } case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:if(Y2 < H2*24-23 || Y2 > H2*24) Y2 = H2*24-24;if(Y2 < H2*24) Y2++;TEMP = 9;//if(Hour == 23) TEMP = 3;else TEMP = 9; } Draw_BMP_For_Scroll(22, 16, Scroll_Digit_BMP[0], Y2, 20, 24, TEMP*24+23);//end_line=Temp*24+23,Scroll_Digit_Small_BMP划到Temp*24+23行,即0~Temp switch(M1) { case 0:if(Y3 < 24*5+1) Y3 = 24*5;if(Y3 < 24*5+24) Y3++;break; case 1: case 2: case 3: case 4: case 5:if(Y3 < M1*24-23 || Y3 > M1*24) Y3 = M1*24-24;if(Y3 < M1*24) Y3++; } Draw_BMP_For_Scroll(50, 16, Scroll_Digit_BMP[0], Y3, 20, 24, 5*24+23);//end_line=5*24+23,Scroll_Digit_Small_BMP划到5*24+23行,即0~5 switch(M2) { case 0:if(Y4 < 24*9+1) Y4 = 24*9;if(Y4 < 24*9+24) Y4++;break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:if(Y4 < M2*24-23 || Y4 > M2*24) Y4 = M2*24-24;if(Y4 < M2*24) Y4++; } Draw_BMP_For_Scroll(72, 16, Scroll_Digit_BMP[0], Y4, 20, 24, 9*24+23);//end_line=9*24+23,Scroll_Digit_Small_BMP划到9*24+23行,即0~9 switch(S1) { case 0:if(Y5 < 16*5+1) Y5 = 16*5;if(Y5 < 16*5+16) Y5++;break; case 1: case 2: case 3: case 4: case 5:if(Y5 < S1*16-15 || Y5 > S1*16) Y5 = S1*16-16;if(Y5 < S1*16) Y5++; } Draw_BMP_For_Scroll(94, 24, Scroll_Digit_Small_BMP[0], Y5, 14, 16, 5*16+15);//end_line=6*16+15,Scroll_Digit_Small_BMP划到6*16+15行,即0~6 switch(S2) { case 0:if(Y6 < 16*9+1) Y6 = 16*9;if(Y6 < 16*9+16) Y6++;break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:if(Y6 < S2*16-15 || Y6 > S2*16) Y6 = S2*16-16;if(Y6 < S2*16) Y6++; } Draw_BMP_For_Scroll(111, 24, Scroll_Digit_Small_BMP[0], Y6, 14, 16, 9*16+15);//end_line=9*16+15,Scroll_Digit_Small_BMP划到9*16+15行,即0~9 if(Second % 2 == 1) OLED_DrawBMP(44,16,4,24,Colon_BMP[0]); //绘制冒号 else OLED_AreaClear(44,16,4,24); //清除冒号 OLED_RefreshPartRAM(2,4,0,127); } ``` 3.RTC获取时间并传递给OLED屏(整体主函数) ```c #include
#include
#include
#include "drv_gpio.h" //导入头文件 #include "oled.h" extern uint8_t Hour,Minute,Second;//时间参数 extern uint8_t H1,H2,M1,M2,S1,S2;//时钟时分秒六位数字 #define LED_PIN GET_PIN(0, 0) //获取到LED0 即P0.0的编号 time_t now; struct tm* Inow; #define THREAD_PRIORITY 25 #define THREAD_STACK_SIZE 512 #define THREAD_TIMESLICE 5 static rt_thread_t tid1 = RT_NULL; /* 获取时间线程的入口函数 */ static void thread1_entry(void *parameter) { rt_uint32_t count = 0; /* 设置时间为11点15分50秒 */ set_time(20, 15, 00); while (1) { /* 获取时间 */ now = time(RT_NULL); Inow=localtime(&now); Hour = Inow->tm_hour; Minute = Inow->tm_min; Second = Inow->tm_sec; H1=Hour/10; /* 小时的十位 */ H2=Hour%10; /* 小时的个位 */ M1=Minute/10; /* 分钟的十位 */ M2=Minute%10; /* 分钟的个位 */ S1=Second/10; /* 秒数的十位 */ S2=Second%10; /* 秒数的个位 */ rt_thread_mdelay(1000); } } static char thread2_stack[1024]; static struct rt_thread thread2; /* 滚动效果线程入口 */ static void thread2_entry(void *param) { OLED_Init(); while(1) { /* 每5ms调用一次滚动效果 */ Draw_Rolling_Clock(); rt_thread_mdelay(5); } } int main(void) { rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); //配置为输出模式 /* 创建获取时间的线程,名称是 thread1,入口是 thread1_entry*/ tid1 = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); /* 启动线程1 */ if (tid1 != RT_NULL) rt_thread_startup(tid1); /* 初始化线程 2,名称是 thread2,入口是 thread2_entry */ rt_thread_init(&thread2, "thread2", thread2_entry, RT_NULL, &thread2_stack[0], sizeof(thread2_stack), THREAD_PRIORITY - 1, THREAD_TIMESLICE); rt_thread_startup(&thread2); for (;;) { rt_thread_mdelay(1000); /* 展示时间 */ rt_kprintf("Hour:%d,Minute:%d,Second:%d\r\n",Hour, Minute, Second); } } ```
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
yhn849673096
这家伙很懒,什么也没写!
文章
1
回答
0
被采纳
0
关注TA
发私信
相关文章
1
stm32f407+lan8720 lwip2.0 作业提交
2
玩溜GD32303E-EVAL BSP系列(五)----设备连接网络
3
onenet应用连不上云端
4
【文件系统】晴天文件匹配
5
rtt semc sdram 基于操作系统怎么初始化驱动设备
6
RT-Thread移植笔记
7
RT-Thread内核移植+LoIIs+STM32F103C8+StdLib
8
EVN编译报错,求助大神
9
【内核和外设学习营】十里 简单LED闪亮测试
10
【内核和外设学习营】 十里 串口指令控制RGB灯点亮的颜色
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部