設計背景
我組大部分成員皆是初次接觸嵌入式開發系統,因此根據本次夏令營學習及導師推薦下我們選擇了設計難度較低的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屏
RT-THREAD Studio軟件包設置
其中參考了SSD1306軟件包及RTC例程因此SSD1306軟件包需單獨下載
開發心得
作為初次接觸嵌入式操作系統的初學者,學習中有些許困難。主要在于不能清楚的掌握模塊的調用,初次接觸線程的概念、使用經過rtt封裝過的C語言頭文件及rtt中的基本函數。在大致讀懂后明白了rtt已經將許多模塊寫好可以直接調用,各位前輩的軟件包是的開發更具模塊化。裸機開發與嵌入式操作系統開發的區別很大但EOS的簡潔明了顯而易見,不過代碼的移植也是入門的難點之一。
下附完整的工程代碼
工程代碼
1.OLED屏驅動
#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 : 全屏填充 0x000xff127, y:0
*/
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:063);127, y:0
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:063);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
ch[] -- 要顯示的字符串;
TextSize -- 字符大小(1:68 ; 2:816)
return : none
Description : 顯示codetab.h中的ASCII字符,有68和816可選擇
/
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] != '?')
{
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] != '?')
{
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+m8, (F8X16[c][n+m8] >> i) & 0x01);
}
}
}
x += 8;
j++;
}
}break;
}
}
}
/
Prototype : void OLED_ShowCN(int16_t x, int16_t y, uint8_t ch)
Parameters : x,y -- 起始點坐標(x:0127, y:07);
CN[]:漢字在codetab.h中的索引
return : none
Description : 顯示codetab.h中的漢字,1616點陣
/
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] != '?')
{
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+m8, (F16x16_CN[i].encoder[n+m16] >> 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+m8, (F16x16_CN[i].encoder[n+m16] >> j) & 0x01);
}
}
}
x += 16;
len++;
break;
}
}
}
}
}
/ ***
Prototype : void OLED_Show_MixedCH(int16_t x, int16_t y, uint8_t* ch)
Parameters : x,y -- 起始點坐標(x:0127, y:07); CN[]:漢字在codetab.h中的索引
return : none
Description : 顯示codetab.h中的漢字,1616點陣,英文,816點陣
/
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] != '?')
{
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+m8, (F16x16_CN[i].encoder[n+m16] >> 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+m8, (F8X16[c][n+m8] >> 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.屏幕數字滾動
#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屏(整體主函數)
#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:%drn",Hour, Minute, Second);
}
}
評論
查看更多