[nRF51822] 1、一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO
最近用nRF51822写了个天马4线SPI的1.77寸LCD彩屏驱动,效果如下:
屏幕的规格资料为:http://pan.baidu.com/s/1gdfkr5L
屏幕的驱动资料为:http://pan.baidu.com/s/1dD3AUFB
工程结构为:
main.c是main函数所在,程序入口
core文件夹中是nrf51822的启动文件,不必看
lib中:
nrf_delay.c是一个简单的延时函数(while循环延时,不精准)
font.c存放一种字体,供屏幕显示用(屏幕每种字体都会对应一种字体资源,字体是一个个01点阵)
代码详解:
main.c中只看main函数即可~(上面相关函数是main函数中被注释掉部分调用实现一个稍微复杂的动画用的)
- int main(void)
- {
- unsigned int x,y,cnt;
- int dis;
- double my_time;
- myDis.cen_x=COL/;
- myDis.cen_y=ROW-;
- myDis.dir=;
- myDis.pre_dir=;
- myDis.len=;
- myDis.dir_change=;
- 15 GPIO_Init();
- 16 LCD_Init();
- 17 DispColor(RED);
- x=y=cnt=;
- dis=;
- my_time=;
- // while(1<2)
- // {
- // cnt++;
- // myDis.pre_dir=myDis.dir;
- // myDis.dir=cnt%4;
- // DispInt(cnt,COL/2-FONT_W*2,ROW,BLUE,RED);
- // DispStr("X-CASE",x,y,BLACK,RED);
- // drawDIS(1);
- // x+=dis*1;
- // y+=dis*2;
- // if(x>=COL-FONT_W*6)
- // {
- // dis=-1;
- // }
- // if(x<=0)
- // {
- // dis=1;
- // }
- // nrf_delay_ms(100);
- // }
- while(<)
- {
- my_time+=0.1;
- //DrawLine(x,x+30,y,y+30,RED);
- x=*cos(my_time)+my_time;
- y=*sin(my_time)+;
- //nrf_delay_ms(10);
- if(my_time<)DrawLine(x,x+,y,y+,BLUE);
- else if(my_time<)DrawLine(x,x+,y,y+,GREEN);
- else if(my_time<)DrawLine(x,x+2,y,y+2,BLACK);
- else {
- 57 DispColor(RED);
- my_time=;
- }
- }
- }
nrf_delay.c中是一个简单延时函数:
- #include "compiler_abstraction.h"
- #include "nrf.h"
- #include "nrf_delay.h"
- /*lint --e{438} "Variable not used" */
- void nrf_delay_ms(uint32_t volatile number_of_ms)
- {
- while(number_of_ms != )
- {
- number_of_ms--;
- nrf_delay_us();
- }
- }
下面重点看nrf_lcd部分:
先看.H文件:
- #ifndef _NRF_LCD_H
- #define _NRF_LCD_H
- #include "pca10001.h"
- #include "nrf_gpio.h"
- #include "nrf_delay.h"
- #include "font.h"
- /*
- 引脚高低电平宏定义
- */
- #define CS_SET nrf_gpio_pin_set(CS)
- #define CS_CLEAR nrf_gpio_pin_clear(CS)
- #define RS_SET nrf_gpio_pin_set(RS)
- #define RS_CLEAR nrf_gpio_pin_clear(RS)
- #define RET_SET nrf_gpio_pin_set(RET)
- #define RET_CLEAR nrf_gpio_pin_clear(RET)
- #define SCL_SET nrf_gpio_pin_set(SCL)
- #define SCL_CLEAR nrf_gpio_pin_clear(SCL)
- #define SDA_SET nrf_gpio_pin_set(SDA)
- #define SDA_CLEAR nrf_gpio_pin_clear(SDA)
- /*
- 宏定义等待函数
- */
- #define DELAY_MS(n) nrf_delay_ms(n)
- //------------------------------------------------------
- #define PIC_WIDTH 160 //预备向LCD显示区域填充的图片的大小
- #define PIC_HEIGHT 160
- #define ROW 160 //显示的行、列数
- #define COL 128
- #define BLUE 0xF800 //定义颜色常量
- #define GREEN 0x07E0
- #define RED 0x001F
- #define WHITE 0xFFFF
- #define BLACK 0x0000
- #define GRAY 0xEF5D //0x2410
- #define GRAY75 0x39E7
- #define GRAY50 0x7BEF
- #define GRAY25 0xADB5
- void GPIO_Init(void);
- void LCD_Init(void);
- void DispColor(unsigned int color);
- void DispInt(unsigned int i, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor);
- void DispStr(unsigned char *str, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor);
- void DrawLine(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend, unsigned int color);
- #endif
1、其中引脚高低电平宏定义是将控制LCD的5条线的引脚的高低电平用宏定义,方便移植
2、将nrf_delay中的毫秒延时函数也用宏定义为DELAY_MS也是方便移植
3、这里PIC_WIDTH和PIC_HEIGHT没用~是我的大的工程中用的~表示一个图片的大小,不必看
4、ROW和COL表示屏幕的长和宽
5、37~45行是常用颜色定义
6、48~53是对外的函数,要想用屏幕首先要调用GPIO初始化函数,然后调用LCD初始化函数将LCD屏幕显示属性的一些命令传送给屏幕,最后可以调用dispcolor将整个屏幕显示一种颜色,调用dispInt显示一个int的数值在屏幕上,dispstr将一个字符串显示在屏幕上(不要觉得这两个函数不起眼,其实要有字库支持,不像你平时在高级的操作系统上调用print那么简单),这里drawline函数不仅可以绘制直线,还能绘制矩形,直线的宽度变宽就变成矩形了~呵呵
在.c中则是上面函数的具体实现:
首先看GPIO初始化函数:
- void GPIO_Init()
- {
- nrf_gpio_cfg_output(CS);
- nrf_gpio_cfg_output(RS);
- nrf_gpio_cfg_output(RET);
- nrf_gpio_cfg_output(SCL);
- nrf_gpio_cfg_output(SDA);
- }
1、该函数是将我们对屏幕控制的5条线设置成输出模式,这个和nRF51822系统相关,要根据nRF限制进行设置,51单片机则不用设置引脚模式,stm则需要设置引脚模式
2、这里的CS\RS等引脚是在pca10001.h中定义的,也就是指定用nRF51的哪些引脚,这里可见用了第10、11、13、14、15五个引脚
接着看模拟的SPI发送一个字节的函数:
- void SendDataSPI(unsigned char dat)
- {
- unsigned char i;
- for(i = ; i < ; i++)
- {
- if( (dat & 0x80) != ) SDA_SET;
- else SDA_CLEAR;
- dat <<= ;
- SCL_CLEAR;
- SCL_SET;
- }
- }
1、这个是根据屏幕驱动协议ILI9163文档中要求而写的通信底层协议
2、函数中将dat的8位从高到底发送出去,11、12行SCL变化一次将数据发送出去一位
3、接下来会基于这个函数实现向LCD屏幕的写数据和写命令函数,然后又基于写数据和写命令函数封装成绘制图形的函数
5.1、dispint是用一个4位的形式显示一个整数,不足的补零
5.2、dispstr是显示一个字符串
5.3、drawline不仅能绘制直线还能绘制矩形
4.1、putpixel是绘制一个像素点,和底层writeonedot不同就在于先调用blockwrite刷新了该点的区域
4.2、dispcolor是将整个屏用一种颜色刷屏
4.3、disonechar是显示一个字符
3.1、blockwrite相当于擦除,每次要对大范围的区域进行刷新前都要调用这个函数进行“擦除”
可见更高层的函数都调用了这个函数,因为无论是显示字符还是绘制区域都要先“擦除”
3.2、lcd_init是屏幕初始化函数
2.1、写命令和写数据函数是基于SPI发送一字节函数写的
2.2、writeonedot函数是填充一像素点数据,上面绘制直线和绘制字符都用到了它
1、SPI发送一字节的底层通信函数
从下到上依次为:数据传输实现层、基础数据段传输封装层、高级数据段传输封装层、基础应用层、高级应用层
- 高级数据段传输封装层
- void WriteComm(unsigned int i)
- {
- CS_CLEAR;
- RS_CLEAR;
- SendDataSPI(i);
- CS_SET;
- }
- void WriteData(unsigned int i)
- {
- CS_CLEAR;
- RS_SET;
- SendDataSPI(i);
- CS_SET;
- }
- void WriteOneDot(unsigned int color)
- {
- CS_CLEAR;
- RS_SET;
- SendDataSPI(color >> );
- SendDataSPI(color);
- CS_SET;
- }
- 高级数据段传输封装层
- /*
- LCD初始化函数
- */
- void LCD_Init(void)
- {
- DELAY_MS();
- RET_SET;
- DELAY_MS();
- RET_CLEAR;
- DELAY_MS();
- RET_SET;
- DELAY_MS();
- //-------------Start Initial Sequence--------//
- WriteComm(0x11); //Exit Sleep
- DELAY_MS();//
- WriteComm(0x26); //Set Default Gamma
- WriteData(0x04);
- WriteComm(0xB1);//Set Frame Rate
- WriteData(0x0B);
- WriteData(0x14);
- WriteComm(0xC0); //Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD
- WriteData(0x0C);
- WriteData(0x05);
- WriteComm(0xC1); //Set BT[2:0] for AVDD & VCL & VGH & VGL
- WriteData(0x02);
- WriteComm(0xC5); //Set VMH[6:0] & VML[6:0] for VOMH & VCOML
- WriteData(0x3F);//
- WriteData(0x48);
- WriteComm(0xC7);// Set VMF
- WriteData(0xC2);
- WriteComm(0x2A); //Set Column Address
- WriteData(0x00);
- WriteData(0x00);
- WriteData(0x00);
- WriteData(0x7F);
- WriteComm(0x2B); //Set Page Address
- WriteData(0x00);
- WriteData(0x00);
- WriteData(0x00);
- WriteData(0x9F);
- WriteComm(0x3A); //Set Color Format
- WriteData(0x55);
- WriteComm(0x36);
- WriteData(0xC8);
- WriteComm(0xF2); //Enable Gamma bit
- WriteData(0x01);
- WriteComm(0xE0);
- WriteData(0x3F);//p1
- WriteData(0x25);//p2
- WriteData(0x21);//p3
- WriteData(0x24);//p4
- WriteData(0x1D);//p5
- WriteData(0x0D);//p6
- WriteData(0x4C);//p7
- WriteData(0xB8);//p8
- WriteData(0x38);//p9
- WriteData(0x17);//p10
- WriteData(0x0F);//p11
- WriteData(0x08);//p12
- WriteData(0x04);//p13
- WriteData(0x02);//p14
- WriteData(0x00);//p15
- WriteComm(0xE1);
- WriteData(0x00);//p1
- WriteData(0x1A);//p2
- WriteData(0x1E);//p3
- WriteData(0x0B);//p4
- WriteData(0x12);//p5
- WriteData(0x12);//p6
- WriteData(0x33);//p7
- WriteData(0x47);//p8
- WriteData(0x47);//p9
- WriteData(0x08);//p10
- WriteData(0x20);//p11
- WriteData(0x27);//p12
- WriteData(0x3C);//p13
- WriteData(0x3D);//p14
- WriteData(0x3F);//p15
- WriteComm(0x36); //MX, MY, RGB mode
- WriteData(0xC0);//c8竖屏 68横屏
- WriteComm(0x29); // Display On
- WriteComm(0x2C);
- }
- /*
- LCD块写(大量数据修改,相当于擦除)
- */
- void BlockWrite(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend)
- {
- //ILI9163C
- WriteComm(0x2A);
- WriteData(Xstart >> );
- WriteData(Xstart);
- WriteData(Xend >> );
- WriteData(Xend);
- WriteComm(0x2B);
- WriteData(Ystart >> );
- WriteData(Ystart);
- WriteData(Yend >> );
- WriteData(Yend);
- WriteComm(0x2c);
- }
注:在LCD初始化函数和blockwrite函数中经常会看到writecomm或者部分writedata参数有些是很奇怪的数据,如0x2A,0x2B...其实这些是屏幕驱动芯片所规定的一些寄存器的地址和这些寄存器的配置数值。这里屏幕初始化就是按照屏幕驱动芯片规格来配置的~而块写这个功能的实现也是要严格按照屏幕驱动说明的!!!反正,玩硬件少不了和各种文档打交道!!!
- 基础应用层
- /*
- 绘制一个像素点
- */
- void PutPixel(unsigned int x, unsigned int y, unsigned int color)
- {
- BlockWrite(x, x, y, y);
- CS_CLEAR;
- RS_SET;
- SendDataSPI(color >> );
- SendDataSPI(color);
- CS_SET;
- }
- /*
- LCD显示颜色(颜色已在.h文件中定义)
- */
- void DispColor(unsigned int color)
- {
- unsigned int i, j;
- BlockWrite(, COL - , , ROW - );
- CS_CLEAR;
- RS_SET;
- for(i = ; i < ROW; i++)
- {
- for(j = ; j < COL; j++)
- {
- SendDataSPI(color >> );
- SendDataSPI(color);
- }
- }
- CS_SET;
- }
- void DispOneChar(unsigned char ord, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor) // ord:0~95
- {
- unsigned char i, j;
- unsigned char *p;
- unsigned char dat;
- unsigned int index;
- BlockWrite(Xstart, Xstart + (FONT_W - ), Ystart, Ystart + (FONT_H - ));
- index = ord;
- if(index > ) //95:ASCII CHAR NUM
- index = ;
- index = index * ((FONT_W / ) * FONT_H);
- p = ascii;
- p = p + index;
- for(i = ; i < (FONT_W / * FONT_H); i++)
- {
- dat = *p++;
- for(j = ; j < ; j++)
- {
- if((dat << j) & 0x80)
- {
- WriteOneDot(TextColor);
- }
- else
- {
- WriteOneDot(BackColor);
- }
- }
- }
67 }
注:1、可见基础应用层都在绘制前先调用了块写,并且下面准备用多大区域就用块写写对应多大区域
注:2、绘制一像素点的升级版是填充整个屏幕,不同是不必for循环调用绘制一像素来实现刷屏,而是直接先块写然后刷屏
注:3、显示一个字符需要调用字库,字库格式如下:
- 高级应用层
- void DispInt(unsigned int i, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor)
- {
- if(Xstart > ((COL - ) - FONT_W * ))
- {
- Xstart = (COL - ) - FONT_W * ;
- }
- if(Ystart > ((ROW - ) - FONT_H))
- {
- Ystart = (Ystart - ) - FONT_H;
- }
- DispOneChar((i >> ) % , Xstart, Ystart, TextColor, BackColor); //ID value
- DispOneChar((i >> ) % , Xstart + FONT_W, Ystart, TextColor, BackColor);
- DispOneChar((i >> ) % , Xstart + FONT_W * , Ystart, TextColor, BackColor);
- DispOneChar(i % , Xstart + FONT_W * , Ystart, TextColor, BackColor);
- BlockWrite(, COL - , , ROW - );
- }
- void DispStr(unsigned char *str, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor)
- {
- while(!(*str == '\0'))
- {
- DispOneChar(ToOrd(*str++), Xstart, Ystart, TextColor, BackColor);
- if(Xstart > ((COL - ) - FONT_W))
- {
- Xstart = ;
- Ystart = Ystart + FONT_H;
- }
- else
- {
- Xstart = Xstart + FONT_W;
- }
- if(Ystart > ((ROW - ) - FONT_H))
- {
- Ystart = ;
- }
- }
- BlockWrite(, COL - , , ROW - );
- }
- /*
- 绘制一片区域(名字为线,其实可以刷一个面)
- */
- void DrawLine(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend, unsigned int color)
- {
- unsigned int i, j;
- BlockWrite(Xstart, Xend, Ystart, Yend);
- for(i = Ystart; i < Yend + ; i++)
- {
- for(j = Xstart; j < Xend + ; j++)
- {
- WriteOneDot(color);
- }
- }
- }
注:1、无论是写一个字符还是写字符串或是整数,最麻烦的不过是计算所需要的像素区域的值位于字库的哪里,所以里面多了很多计算~
注:2、绘制直线和区域填充类似,只是区域填充直接调用底层SPI数据传输函数,这里调用了writeonedot函数。我觉得也可以直接调用底层,也许会加快绘制速度!
小结
上面一个小小的驱动函数组织不算完美,我只是用厂家给的demo移植到nRF上,所以函数调用有点乱~
用nRF51822四线SPI驱动1.77寸(128X160像素,每个像素需要16位数据)刷屏的速度人是可以感知的!
因此,如果想利用它来做复杂的动画就有点难度了~
而我目前正遇到这个难题~攻克中!!!
该nRF51822晶振是16M的,刷一张图时间大概0.8s左右,接下来我将用stm32,72M的试试~
上述工程代码:http://pan.baidu.com/s/1bnHmi55
@beautifulzzzz
2015-11-25 持续更新中~
[nRF51822] 1、一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO的更多相关文章
- [stm32] 一个简单的stm32vet6驱动的天马4线SPI-1.77寸LCD彩屏DEMO
书接上文<1.一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO> 我们发现用16MHz晶振的nRF51822驱动1.77寸的spi速度达不到要求 本节主要采用7 ...
- [stm32] 一个简单的stm32vet6驱动2.4寸240X320的8位并口tft屏DEMO
书接上文: 最近在研究用低速.低RAM的单片机来驱动小LCD或TFT彩屏实现动画效果 首先我用一个16MHz晶振的m0内核的8位单片机nRF51822尝试驱动一个1.77寸的4线SPI屏(128X16 ...
- 如何编写一个简单的Linux驱动(二)——设备操作集file_operations
前期知识 如何编写一个简单的Linux驱动(一)--驱动的基本框架 前言 在上一篇文章中,我们学习了驱动的基本框架.这一章,我们会在上一章代码的基础上,继续对驱动的框架进行完善.要下载上一篇文章的全部 ...
- 如何编写一个简单的Linux驱动(二)——完善设备驱动
前期知识 1.如何编写一个简单的Linux驱动(一)——驱动的基本框架 2.如何编写一个简单的Linux驱动(二)——设备操作集file_operations 前言 在上一篇文章中,我们编写设备驱动遇 ...
- 如何编写一个简单的Linux驱动(一)
前言 最近在学习Linux驱动,记录下自己学习的历程. 驱动的基本框架 Linux驱动的基本框架包含两部分,“模块入口.出口的注册”和“模块入口.出口函数的实现”,如下方代码. static int ...
- Linux下GPIO驱动(一) ----一个简单的LED驱动
/******************************* * *杂项设备驱动:miscdevice *majior=10; * * *****************************/ ...
- linux设备驱动归纳总结(五):4.写个简单的LED驱动【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-84693.html linux设备驱动归纳总结(五):4.写个简单的LED驱动 xxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(五):4.写个简单的LED驱动
linux设备驱动归纳总结(五):4.写个简单的LED驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- Shiro —— 从一个简单的例子开始
一.Shiro是用来做权限的. 二.权限 1.基本概念: (1)安全实体:要保护的数据. (2)权限:是否有能力去操作(查看.修改.删除 )保护的数据. 2.权限的两个特性 (1)权限的继承性:A 包 ...
随机推荐
- 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)'
error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Tra ...
- ASP.NET操作ORACLE数据库之模糊查询
ASP.NET操作ORACLE数据库之模糊查询 一.ASP.NET MVC利用OracleHelper辅助类操作ORACLE数据库 //连接Oracle数据库的连接字符串 string connect ...
- NOIP2014 总结
想了很久,才开始动笔. 怎么说,感觉挺对不起自己的.愚蠢的失误让我正好卡着一等线,真希望不要是二等奖. 最难过的是,努力全葬送在愚蠢上面了. 不过也好,学会平静自己也是一种能力. 半期考试也遭的一塌糊 ...
- IIS出现 分析器错误消息: 在应用程序级别之外使用注册为 allowDefinition='MachineToApplication' 的节是错误的
这是因为发布的时候按了“生成部署包”
- css3动画之图片旋转
直接上代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- Swift:subscript
本文转载自:http://blog.csdn.net/sinat_27706697/article/details/47122137 感谢作者:秋恨雪 通常情况下,我们在使用数组(Array)或字典( ...
- 使用CSS设置行间距,字间距.
字间距1.text-indent设置抬头距离css缩进即对,对应div设置css样式text-indent : 20px; 缩进了20px 2.letter-spacing来设置字与字间距_字符间距离 ...
- REST,RESTful
REST(Representational State Transfer)描述了一个架构样式的网络系统. RESTful架构,就是目前最流行的一种互联网软件架构.结构清晰.符合标准.易于理解.扩展方便 ...
- Python socket (多线程)
Server 端 code import SocketServer class MyTCPHandler(SocketServer.BaseRequestHandler): ""& ...
- IOS和Android支持的音频编解码
1.IOS编码 参考文档地址:https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/Multimedi ...