/*** @brief This function handles System tick timer.*/voidSysTick_Handler(void){/* USER CODE BEGIN SysTick_IRQn 0 *//* USER CODE END SysTick_IRQn 0 */HAL_IncTick();/* USER CODE BEGIN SysTick_IRQn 1 */OledTimeMsFunc();/* USER CODE END SysTick_IRQn 1 */}
修改OLED_Init函數(shù)
voidOLED_Init(void){WriteCmd(0xAE);//display offWriteCmd(0x20);//Set Memory Addressing Mode// WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0x00);//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0xb0);//Set Page Start Address for Page Addressing Mode,0-7WriteCmd(0xc8);//Set COM Output Scan DirectionWriteCmd(0x00);//---set low column addressWriteCmd(0x10);//---set high column addressWriteCmd(0x40);//--set start line addressWriteCmd(0x81);//--set contrast control registerWriteCmd(0xff);//亮度調(diào)節(jié) 0x00~0xffWriteCmd(0xa1);//--set segment re-map 0 to 127WriteCmd(0xa6);//--set normal displayWriteCmd(0xa8);//--set multiplex ratio(1 to 64)WriteCmd(0x3F);//WriteCmd(0xa4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM contentWriteCmd(0xd3);//-set display offsetWriteCmd(0x00);//-not offsetWriteCmd(0xd5);//--set display clock divide ratio/oscillator frequencyWriteCmd(0xf0);//--set divide ratioWriteCmd(0xd9);//--set pre-charge periodWriteCmd(0x22);//WriteCmd(0xda);//--set com pins hardware configurationWriteCmd(0x12);WriteCmd(0xdb);//--set vcomhWriteCmd(0x20);//0x20,0.77xVccWriteCmd(0x8d);//--set DC-DC enableWriteCmd(0x14);//WriteCmd(0xaf);//--turn on oled panelOLED_CLS();}
/*Copyright (c) [2019] [一只程序緣 jiezhuo][https://gitee.com/jiezhuonew/oledlib] is licensed under the Mulan PSL v1.You can use this software according to the terms and conditions of the Mulan PSL v1.You may obtain a copy of Mulan PSL v1 at:http://license.coscl.org.cn/MulanPSLTHIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULARPURPOSE.See the Mulan PSL v1 for more details.==========此函數(shù)是oledlib圖形庫的綜合測試函數(shù) 基本上使用到了里面的所有內(nèi)容==================目前接線說明:僅僅使用到0.96寸7引腳oled 使用SPI通信方式(具體見oled_drive.c)D0 = SCK -> PA4 (屏幕批次不同絲印可能不同)D1 = SDA -> PA5RES = RES -> PA6DC = DC -> PA7CS = SCS -> PA8軟件模塊:oled spi驅(qū)動beep 蜂鳴器 提示或作為led表示運行狀態(tài)timer3 中斷1ms 可為圖形庫提供時間基準uart 可作為串口連接電腦打印調(diào)試xinxidelay 系統(tǒng)自帶的時間設置與提供延時函數(shù)視頻演示信息:單片機 --- STM32F103oled --- 采用4線SPI的7引腳0.96寸黑白雙色oled圖形庫功能:在oledlib文件夾下作出多個c文件的分類 每個c文件的開頭都有對該文件的簡要說明包括打點 畫線 矩形 三角形 圓 橢圓 圓角矩形 的邊緣與填充還包括 字符顯示 漢字顯示 位圖顯示最后還有 oled模擬串口printf的debug字符顯示:針對于字符有4種大小0-1-2-3 具體參見SetFontSize()基于大家的使用習慣0是一般大家習慣用的 此時y只能為0-7對應顯示的7大行 注意:此時x為地基大行 y為第幾列2 3都是基于1的等比例放大 此時y能為0-6x對應顯示的每一小行 此時為正常坐標系 x為第幾小行 y為第幾列中文漢字顯示:中文漢字的大小為16x16 此時y也只能為0-7對應顯示的7大行 注意:此時x為地基大行 y為第幾列取模說明:取模軟件采用PCtoLCD2002字符 漢字 和 位圖的取模方式和設置都在font.c和bmp.c中有注釋用戶調(diào)用函數(shù):在draw_api.h中提供了所有函數(shù)的接口 可在其中查看所有函數(shù)的簡要功能移植說明:1.移植圖形庫僅需要準備好底層驅(qū)動 在oled_driver.c中作出修改即可 在該c文件開頭有說明2.若需要對test.c中的動畫效果進行測試 還需要為函數(shù)OledTimeMsFunc()提供時間基準3.庫函數(shù)使用的延時函數(shù)是DelayMs() 移植后由單片機型號補充調(diào)整DelayMs()圖形庫本質(zhì):該圖形庫本質(zhì)為對一數(shù)組進行操作 然后刷新整個數(shù)組到屏幕中實現(xiàn)效果因此相似點陣屏(oled/TFT/大小尺寸/點陣/液晶)也可以使用 根據(jù)像素可參見oled_config.h詳細的注釋:如果是使用為用途 了解test.c和draw_api.c即可 做出花里胡哨的UI界面在本人閱讀代碼和注釋的過程中 發(fā)現(xiàn)很多結構和函數(shù)都值得學習 仔細理解理解GUI和本圖形庫的關系:gui是一個以圖形界面來進行人機交互的系統(tǒng) gui是擁有窗口、菜單、控件、對話框等交互的圖形接口這個只是一個圖形庫 類似于c++上的easyx圖形庫 是沒有圖形接口的 只提供繪圖和顯示的功能圖形庫可以算是gui的一部分,也可以自己以圖形庫繼續(xù)封裝為gui庫代碼容量:除去位圖 Code=26254 RO-data=3754 RW-data=100 ZI-data=4108原作的話:為了做這個繪制圖形庫,我參考了很多其他的算法,花了大量時間去做移植優(yōu)化,其中參考最多的是github中的arduboy游戲機,大部分圖形是移植它的,現(xiàn)在是最初的初稿版本,還有很多地方需要優(yōu)化改進。我想要將這個圖形庫做大,后續(xù)會加入更多有趣的東西,和模塊,代碼都是用最簡單的方式編寫的,都是開源的。后續(xù)也會加上注釋說明,讓更多人以單片機和oled屏來入門硬件編程,如果你使用了該庫,請標明出處。b站關注oximeterg,可獲取該庫的最新版本和消息。注意:繪制填充或?qū)嵭牡膱D形,影響刷新效率(待優(yōu)化中)
*/// #include "test.h"#include"draw_api.h"#include"../Delay/Delay.h"#include"stdlib.h"#include"stdio.h"#include"math.h"voidShowStars(void);voidShowWatch(void);voidShowPolygon(void);voidShowSnow(void);voiddemo(void){int i,j;//demo演示ClearScreen();DrawBitmap(0,0,Panda,128,64);UpdateScreen();DelayMs(1000);//字符ClearScreen();SetFontSize(1);DrawString(0,0,"test");UpdateScreen();DelayMs(1000);SetFontSize(2);DrawString(0,8,"test");UpdateScreen();DelayMs(1000);SetFontSize(3);DrawString(0,24,"test");UpdateScreen();DelayMs(1000);//漢字測試ClearScreen();OLED_ShowCHinese(0,0,"一只程序緣");UpdateScreen();DelayMs(1000);OLED_ShowCHinese(2,0,"一只程序緣一只程序緣一只程序緣一只程序緣");UpdateScreen();DelayMs(1000);//數(shù)字測試ClearScreen();for(i=0; i<300; i++){SetFontSize(0);DrawNum(0,96,i,4);SetFontSize(1);DrawNum(0,16,i,4);SetFontSize(2);DrawNum(0,24,i,4);SetFontSize(3);DrawNum(0,40,i,4);UpdateScreen();}//串口debugDelayMs(100);ClearScreen();for(i=0; i<256; i++){OledPrintf("num:%d cha:%c hex:%x\r\n",i,i,i);}DelayMs(100);//劃線ClearScreen();for(i=0; i<20; i++){DrawLine(0,0,i*10,63);UpdateScreen();}for(i=0; i<20; i++){DrawLine(128,0,128-i*10,63);UpdateScreen();}DelayMs(100);//矩形for(j=0; j<2; j++){if(j==0)ClearScreen();for(i=0; i<31; i+=2){DrawRect2(i*2,i,128-i*4,64-2*i);//畫矩形外框UpdateScreen();}if(j==0)ClearScreen();DelayMs(100);for(i=31; i>0; i-=2){DrawFillRect2(i*2,i,128-i*4,64-2*i);//畫實心矩形UpdateScreen();}SetDrawColor(pix_black);//劃線顏色SetFillcolor(pix_black);//填充顏色}SetDrawColor(pix_white);SetFillcolor(pix_white);//圓角矩形for(j=0; j<2; j++){if(j==0)ClearScreen();for(i=0; i<25; i+=2){DrawRoundRect(i*2,i,128-i*4,64-2*i,8);UpdateScreen();}if(j==0)ClearScreen();DelayMs(100);for(i=25; i>2; i-=2){DrawfillRoundRect(i*2,i,128-i*4,64-2*i,8);UpdateScreen();}SetDrawColor(pix_black);SetFillcolor(pix_black);}SetDrawColor(pix_white);SetFillcolor(pix_white);DelayMs(100);//橢圓ClearScreen();DrawEllipse(63,31,63,31);UpdateScreen();DelayMs(500);ClearScreen();DrawEllipse(63,31,16,31);UpdateScreen();DelayMs(500);ClearScreen();DrawFillEllipse(63,31,63,31);UpdateScreen();DelayMs(500);ClearScreen();DrawFillEllipse(63,31,16,31);UpdateScreen();DelayMs(500);//圓ClearScreen();DrawCircle(63,31,30);UpdateScreen();DelayMs(500);ClearScreen();DrawFillCircle(63,31,30);UpdateScreen();DelayMs(500);//三角形ClearScreen();DrawTriangle(5,10,100,30,60,50);UpdateScreen();DelayMs(500);ClearScreen();DrawFillTriangle(5,10,100,30,60,50);UpdateScreen();DelayMs(500);//繪制圖形圖片 位圖ClearScreen();DrawBitmap(0,0,BmpTest1,16,16);UpdateScreen();DelayMs(500);DrawBitmap(16,0,BmpTest2,32,32);UpdateScreen();DelayMs(500);DrawBitmap(48,0,BmpTest3,64,64);UpdateScreen();DelayMs(500);//圓弧ClearScreen();for(i=0; i<360; i++){DrawArc(63,31,30,0,i);//畫圓弧UpdateScreen();DelayMs(25);ClearScreen();}DrawCircle(63,31,30);//畫圓UpdateScreen();DelayMs(100);for(i=0; i<10; i++){DrawFillCircle(63,31,i);//在中心填充圓DrawCircle(63,31,30);UpdateScreen();DelayMs(25);ClearScreen();}//繞點for(i=0; i<720; i++)//轉(zhuǎn)720度2圈{TypeXY temp;SetAngle(i);//設置角度SetRotateCenter(63,31);//設置圓心temp=GetRotateXY(63,31+30);//講已知坐標旋轉(zhuǎn)角度DrawFillCircle(temp.x,temp.y,5);//畫出算出的位置DrawCircle(63,31,30);//畫出軌跡DrawFillCircle(63,31,10);//填充中心UpdateScreen();//更新屏幕ClearScreen();}//向右邊平移for(i=0; i<95; i++){TypeXY temp;//其實就是上面繼續(xù)旋轉(zhuǎn)SetAngle(720+i);//畫圖的時候x+偏移量SetRotateCenter(63+i,31);temp=GetRotateXY(63+i,31+30);DrawFillCircle(temp.x,temp.y,5);DrawCircle(63+i,31,30);DrawFillCircle(63+i,31,10);UpdateScreen();ClearScreen();}//動畫ShowStars();//星空動畫ShowWatch();//時鐘動畫ShowPolygon();//多邊形動畫// ShowSnow(); //下雪動畫DelayMs(100);//結束ClearScreen();SetFontSize(2);DrawString(8,16," Show End ");//顯示字符串UpdateScreen();DelayMs(1000);ClearScreen();DrawBitmap(0,10,Like,128,40);//三連圖片UpdateScreen();DelayMs(1000);}///星空動畫voidShowStars(void){int i;int count=0;int fps=60;typedefstructSTART{short x;short y;short speed;unsignedchar speedcount;unsignedchar isexist;} Star;Star star[128]={0};srand(2);for(i=0; i<128; i++){if(star[i].isexist==0){//設置128個()星星的初始信息star[i].x=rand()%127;//隨機生成初始x坐標star[i].y=rand()%64;//隨機生成y的坐標star[i].speedcount=0;star[i].speed=rand()%8+1;//1-8的數(shù)star[i].isexist=1;}}while(1){if(FrameRateUpdateScreen(fps)==1)//在此函數(shù)中定時刷新屏{count++;if(count>=fps*10)//10秒鐘時間到達之后跳出循環(huán)結束動畫return;}//此段函數(shù)一直在運行//依次畫出128個星星for(i=0; i<128; i++){//如果這一個星星已經(jīng)移動到退出屏幕界面//則在最左側(cè)重新生成一顆新星星if(star[i].isexist==0){star[i].x=0;star[i].y=rand()%64;star[i].speed=rand()%6+1;star[i].speedcount=0;star[i].isexist=1;}else{star[i].speedcount++;if(star[i].x>=124)//標記已經(jīng)退出屏幕star[i].isexist=0;//清除上一個時刻畫的星星(的尾巴) 不管有沒有操作 都進行清除操作SetDrawColor(pix_black);DrawLine(star[i].x,star[i].y,star[i].x,star[i].y);SetDrawColor(pix_white);if(star[i].speedcount==star[i].speed)//運行時間到了一定的長度{star[i].speedcount=0;//復位運行時間并向右移一格star[i].x+=1;//總之星星的結束需要在這經(jīng)歷124次}//只不過有的更快 就能移動更快//從頭到尾畫出整條星星 不管星星是否已經(jīng)變化DrawLine(star[i].x, star[i].y, star[i].x+(6/star[i].speed)-1, star[i].y);}}}}//時鐘動畫//鐘 小時 分鐘 秒,voidRoundClock(int hours,int minute,int sec){unsignedchar i=0;TypeXY hourspoint,minutepoint,secpoint,tmp1,tmp2;//時針SetRotateValue(63,31,hours*30+(minute*30)/60,1);hourspoint=GetRotateXY(63-14,31);DrawLine(63,31,hourspoint.x,hourspoint.y);//分針SetRotateValue(63,31,minute*6+(sec*6)/60,1);minutepoint=GetRotateXY(63-21,31);DrawLine(63,31,minutepoint.x,minutepoint.y);//秒針SetRotateValue(63,31,sec*6,1);secpoint=GetRotateXY(63-28,31);DrawLine(63,31,secpoint.x,secpoint.y);//表盤for(i=0; i<12; i++){SetRotateValue(63,31,i*30,1);tmp1=GetRotateXY(63-29,31);tmp2=GetRotateXY(63-24,31);DrawLine(tmp1.x,tmp1.y,tmp2.x,tmp2.y);}DrawFillCircle(63,31,2);DrawCircle(63,31,30);UpdateScreen();DelayMs(25);ClearScreen();}voidShowWatch(void){int i,j,z;int count=0;for(i=0; i<12; i++)for(j=0; j<60; j++)for(z=0; z<60; z++){RoundClock(i,j,z);count++;if(count>=800)return;}}///多邊形動畫voidShowPolygon(void){int x0=63,y0=31;//正多邊形的外接圓的圓心unsignedchar i =0,j;int n=1,r=31;//畫正n邊形 大小半徑31int v=1,count=0;//每個相鄰的多邊形隔1 畫count次后退出int x[30],y[30];while(1){ClearScreen();for(i=0; i<n; i++){x[i]=r*cos(2*3.1415926*i/n)+x0;y[i]=r*sin(2*3.1415926*i/n)+y0;}for(i=0; i<=n-2; i++){for(j=i+1; j<=n-1; j++)DrawLine(x[i],y[i],x[j],y[j]);}n+=v;if(n==20||n==0)v=-v;UpdateScreen();DelayMs(25);//延時停頓100msif(++count==90){count=0;return;}}}//下雪的函數(shù) 和星空類似 voidShowSnow(void){int a[66],i,num=0;int count=0;int fps=60;structSnow{short x;short y;short speed;} snow[100];srand(1);for(i=0; i<66; i++)a[i]=(i-2)*10;ClearScreen();while(1){if(FrameRateUpdateScreen(fps)==1)//在此函數(shù)中定時刷新屏{count++;if(count>=fps*10)//10秒鐘時間到達之后跳出循環(huán)結束動畫return;}if(num!=100){snow[num].speed=1+rand()%4;i=rand()%66;snow[num].x=a[i];snow[num].y=0;num++;}for(i=0; i<num; i++){snow[i].y+=snow[i].speed;DrawPixel(snow[i].x,snow[i].y+1);DrawPixel(snow[i].x+1,snow[i].y);DrawPixel(snow[i].x,snow[i].y);DrawPixel(snow[i].x-1,snow[i].y);DrawPixel(snow[i].x,snow[i].y-1);if(snow[i].y>63){snow[i].y=0;}}UpdateScreen();DelayMs(25);ClearScreen();}}
在main.c文件中包含必要的頭文件
//...#include"main.h"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes */#include"../Delay/Delay.h"#include"../oledlib/draw_api.h"/* USER CODE END Includes *///...
添加初始化函數(shù)并測試demo
//.../* USER CODE BEGIN 2 */delay_init();InitGraph();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */voiddemo(void);demo();}/* USER CODE END 3 *///...