开发者社区> 史迪奇2号> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

[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函数中被注释掉部分调用实现一个稍微复杂的动画用的)

复制代码
 1 int main(void)
 2 {
 3     unsigned int x,y,cnt;
 4     int dis;
 5     double my_time;
 6 
 7     myDis.cen_x=COL/2;
 8     myDis.cen_y=ROW-50;
 9     myDis.dir=0;
10     myDis.pre_dir=0;
11     myDis.len=20;
12     myDis.dir_change=1;
13 
14 
15     GPIO_Init();
16     LCD_Init();
17     DispColor(RED);
18     
19     x=y=cnt=0;
20     dis=1;
21     my_time=0;
22 
23 
24 //       while(1<2)
25 //    {
26 //        cnt++;
27 //        myDis.pre_dir=myDis.dir;
28 //        myDis.dir=cnt%4;
29 //        DispInt(cnt,COL/2-FONT_W*2,ROW,BLUE,RED);
30 //        DispStr("X-CASE",x,y,BLACK,RED); 
31 //        drawDIS(1);
32 
33 //        x+=dis*1;
34 //        y+=dis*2;
35 //        if(x>=COL-FONT_W*6)
36 //        {
37 //            dis=-1;    
38 //        }
39 //        if(x<=0)
40 //        {
41 //             dis=1;
42 //        }  
43 //        nrf_delay_ms(100);
44 //    }
45     while(1<2)
46     {
47         my_time+=0.1;
48         //DrawLine(x,x+30,y,y+30,RED);
49         x=60*cos(my_time)+my_time;
50         y=60*sin(my_time)+80;
51         
52         //nrf_delay_ms(10);
53         if(my_time<300)DrawLine(x,x+2,y,y+2,BLUE);
54         else if(my_time<600)DrawLine(x,x+2,y,y+2,GREEN);
55         else if(my_time<900)DrawLine(x,x+2,y,y+2,BLACK);
56         else {
57             DispColor(RED);
58             my_time=0;
59         }
60     }
61 }
复制代码

 

nrf_delay.c中是一个简单延时函数:

复制代码
 1 #include "compiler_abstraction.h"
 2 #include "nrf.h"
 3 #include "nrf_delay.h"
 4 
 5 /*lint --e{438} "Variable not used" */
 6 void nrf_delay_ms(uint32_t volatile number_of_ms)
 7 {
 8   while(number_of_ms != 0)
 9   {
10     number_of_ms--;
11     nrf_delay_us(999);
12   }
13 }
复制代码

 

下面重点看nrf_lcd部分:

先看.H文件:

复制代码
 1 #ifndef _NRF_LCD_H
 2 #define _NRF_LCD_H
 3 
 4 
 5 #include "pca10001.h"
 6 #include "nrf_gpio.h"
 7 #include "nrf_delay.h"
 8 #include "font.h"
 9 /*
10 引脚高低电平宏定义
11 */
12 #define CS_SET        nrf_gpio_pin_set(CS)
13 #define CS_CLEAR     nrf_gpio_pin_clear(CS)  
14 #define RS_SET        nrf_gpio_pin_set(RS)
15 #define RS_CLEAR     nrf_gpio_pin_clear(RS) 
16 #define RET_SET        nrf_gpio_pin_set(RET)
17 #define RET_CLEAR     nrf_gpio_pin_clear(RET)
18 #define SCL_SET        nrf_gpio_pin_set(SCL)
19 #define SCL_CLEAR     nrf_gpio_pin_clear(SCL)   
20 #define SDA_SET        nrf_gpio_pin_set(SDA)
21 #define SDA_CLEAR     nrf_gpio_pin_clear(SDA)
22 /*
23 宏定义等待函数
24 */
25 #define DELAY_MS(n) nrf_delay_ms(n)
26 
27 
28 
29 //------------------------------------------------------
30 #define PIC_WIDTH    160     //预备向LCD显示区域填充的图片的大小
31 #define PIC_HEIGHT   160
32 
33 #define ROW  160            //显示的行、列数
34 #define COL  128
35 
36 
37 #define BLUE   0xF800         //定义颜色常量 
38 #define GREEN  0x07E0
39 #define RED    0x001F
40 #define WHITE  0xFFFF
41 #define BLACK  0x0000
42 #define GRAY   0xEF5D         //0x2410
43 #define GRAY75 0x39E7 
44 #define GRAY50 0x7BEF    
45 #define GRAY25 0xADB5
46 
47 
48 void GPIO_Init(void);
49 void LCD_Init(void);
50 void DispColor(unsigned int color);
51 void DispInt(unsigned int i, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor);
52 void DispStr(unsigned char *str, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor);
53 void DrawLine(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend, unsigned int color);
54 
55 #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初始化函数

复制代码
1 void GPIO_Init()
2 {
3     nrf_gpio_cfg_output(CS);
4     nrf_gpio_cfg_output(RS);
5     nrf_gpio_cfg_output(RET);
6     nrf_gpio_cfg_output(SCL);
7     nrf_gpio_cfg_output(SDA);
8 }
复制代码

1、该函数是将我们对屏幕控制的5条线设置成输出模式这个和nRF51822系统相关,要根据nRF限制进行设置,51单片机则不用设置引脚模式,stm则需要设置引脚模式

2、这里的CS\RS等引脚是在pca10001.h中定义的,也就是指定用nRF51的哪些引脚,这里可见用了第10、11、13、14、15五个引脚

 

接着看模拟的SPI发送一个字节的函数

复制代码
 1 void SendDataSPI(unsigned char dat)
 2 {
 3     unsigned char i;
 4     for(i = 0; i < 8; i++)
 5     {
 6         if( (dat & 0x80) != 0 ) SDA_SET;
 7         else SDA_CLEAR;
 8 
 9         dat <<= 1;
10 
11         SCL_CLEAR;
12         SCL_SET;
13     }
14 }
复制代码

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发送一字节的底层通信函数

 

 

从下到上依次为:数据传输实现层、基础数据段传输封装层、高级数据段传输封装层、基础应用层、高级应用层

 

  • 高级数据段传输封装层
复制代码
 1 void WriteComm(unsigned int i)
 2 {
 3     CS_CLEAR;
 4     RS_CLEAR;
 5     SendDataSPI(i);
 6     CS_SET;
 7 }
 8 void WriteData(unsigned int i)
 9 {
10     CS_CLEAR;
11     RS_SET;
12     SendDataSPI(i);
13     CS_SET;
14 }
15 void WriteOneDot(unsigned int color)
16 {
17     CS_CLEAR;
18     RS_SET;
19 
20     SendDataSPI(color >> 8);
21     SendDataSPI(color);
22 
23     CS_SET;
24 }
复制代码

 

  • 高级数据段传输封装层
复制代码
  1 /*
  2 LCD初始化函数
  3 */
  4 void LCD_Init(void)
  5 {
  6     DELAY_MS(100);
  7     RET_SET;
  8     DELAY_MS(100);
  9     RET_CLEAR;
 10     DELAY_MS(100);
 11     RET_SET;
 12     DELAY_MS(100);
 13 
 14     //-------------Start Initial Sequence--------//
 15     WriteComm(0x11); //Exit Sleep
 16     DELAY_MS(10);//20
 17     WriteComm(0x26); //Set Default Gamma
 18     WriteData(0x04);
 19 
 20     WriteComm(0xB1);//Set Frame Rate
 21     WriteData(0x0B);
 22     WriteData(0x14);
 23 
 24     WriteComm(0xC0); //Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD
 25     WriteData(0x0C);
 26     WriteData(0x05);
 27 
 28     WriteComm(0xC1); //Set BT[2:0] for AVDD & VCL & VGH & VGL
 29     WriteData(0x02);
 30 
 31     WriteComm(0xC5); //Set VMH[6:0] & VML[6:0] for VOMH & VCOML
 32     WriteData(0x3F);//44
 33     WriteData(0x48);
 34 
 35     WriteComm(0xC7);// Set VMF
 36     WriteData(0xC2);
 37 
 38     WriteComm(0x2A); //Set Column Address
 39     WriteData(0x00);
 40     WriteData(0x00);
 41     WriteData(0x00);
 42     WriteData(0x7F);
 43     WriteComm(0x2B); //Set Page Address
 44     WriteData(0x00);
 45     WriteData(0x00);
 46     WriteData(0x00);
 47     WriteData(0x9F);
 48 
 49     WriteComm(0x3A); //Set Color Format
 50     WriteData(0x55);
 51     WriteComm(0x36);
 52     WriteData(0xC8);
 53 
 54     WriteComm(0xF2); //Enable Gamma bit
 55     WriteData(0x01);
 56     WriteComm(0xE0);
 57     WriteData(0x3F);//p1
 58     WriteData(0x25);//p2
 59     WriteData(0x21);//p3
 60     WriteData(0x24);//p4
 61     WriteData(0x1D);//p5
 62     WriteData(0x0D);//p6
 63     WriteData(0x4C);//p7
 64     WriteData(0xB8);//p8
 65     WriteData(0x38);//p9
 66     WriteData(0x17);//p10
 67     WriteData(0x0F);//p11
 68     WriteData(0x08);//p12
 69     WriteData(0x04);//p13
 70     WriteData(0x02);//p14
 71     WriteData(0x00);//p15
 72     WriteComm(0xE1);
 73     WriteData(0x00);//p1
 74     WriteData(0x1A);//p2
 75     WriteData(0x1E);//p3
 76     WriteData(0x0B);//p4
 77     WriteData(0x12);//p5
 78     WriteData(0x12);//p6
 79     WriteData(0x33);//p7
 80     WriteData(0x47);//p8
 81     WriteData(0x47);//p9
 82     WriteData(0x08);//p10
 83     WriteData(0x20);//p11
 84     WriteData(0x27);//p12
 85     WriteData(0x3C);//p13
 86     WriteData(0x3D);//p14
 87     WriteData(0x3F);//p15
 88 
 89 
 90     WriteComm(0x36); //MX, MY, RGB mode
 91     WriteData(0xC0);//c8竖屏  68横屏
 92 
 93     WriteComm(0x29); // Display On
 94 
 95     WriteComm(0x2C);
 96 }
 97 
 98 /*
 99 LCD块写(大量数据修改,相当于擦除)
100 */
101 void BlockWrite(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend)
102 {
103     //ILI9163C
104     WriteComm(0x2A);
105     WriteData(Xstart >> 8);
106     WriteData(Xstart);
107     WriteData(Xend >> 8);
108     WriteData(Xend);
109 
110     WriteComm(0x2B);
111     WriteData(Ystart >> 8);
112     WriteData(Ystart);
113     WriteData(Yend >> 8);
114     WriteData(Yend);
115 
116     WriteComm(0x2c);
117 }
复制代码

注:在LCD初始化函数和blockwrite函数中经常会看到writecomm或者部分writedata参数有些是很奇怪的数据,如0x2A,0x2B...其实这些是屏幕驱动芯片所规定的一些寄存器的地址和这些寄存器的配置数值。这里屏幕初始化就是按照屏幕驱动芯片规格来配置的~而块写这个功能的实现也是要严格按照屏幕驱动说明的!!!反正,玩硬件少不了和各种文档打交道!!!

 

  • 基础应用层
复制代码
 1 /*
 2 绘制一个像素点
 3 */
 4 void PutPixel(unsigned int x, unsigned int y, unsigned int color)
 5 {
 6     BlockWrite(x, x, y, y);
 7     CS_CLEAR;
 8     RS_SET;
 9     SendDataSPI(color >> 8);
10     SendDataSPI(color);
11     CS_SET;
12 }
13 /*
14 LCD显示颜色(颜色已在.h文件中定义)
15 */
16 void DispColor(unsigned int color)
17 {
18     unsigned int i, j;
19     BlockWrite(0, COL - 1, 0, ROW - 1);
20 
21     CS_CLEAR;
22     RS_SET;
23     for(i = 0; i < ROW; i++)
24     {
25         for(j = 0; j < COL; j++)
26         {
27             SendDataSPI(color >> 8);
28             SendDataSPI(color);
29         }
30     }
31     CS_SET;
32 }
33 void  DispOneChar(unsigned char ord, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor)     // ord:0~95
34 {
35     unsigned char i, j;
36     unsigned char  *p;
37     unsigned char dat;
38     unsigned int index;
39 
40     BlockWrite(Xstart, Xstart + (FONT_W - 1), Ystart, Ystart + (FONT_H - 1));
41 
42     index = ord;
43 
44     if(index > 95)     //95:ASCII CHAR NUM
45         index = 95;
46 
47     index = index * ((FONT_W / 8) * FONT_H);
48 
49     p = ascii;
50     p = p + index;
51 
52     for(i = 0; i < (FONT_W / 8 * FONT_H); i++)
53     {
54         dat = *p++;
55         for(j = 0; j < 8; j++)
56         {
57             if((dat << j) & 0x80)
58             {
59                 WriteOneDot(TextColor);
60             }
61             else
62             {
63                 WriteOneDot(BackColor);
64             }
65         }
66     }
67 }
复制代码

注:1、可见基础应用层都在绘制前先调用了块写,并且下面准备用多大区域就用块写写对应多大区域

注:2、绘制一像素点的升级版是填充整个屏幕,不同是不必for循环调用绘制一像素来实现刷屏,而是直接先块写然后刷屏

注:3、显示一个字符需要调用字库,字库格式如下:

 

  • 高级应用层
复制代码
 1 void DispInt(unsigned int i, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor)
 2 {
 3     if(Xstart > ((COL - 1) - FONT_W * 4))
 4     {
 5         Xstart = (COL - 1) - FONT_W * 4;
 6     }
 7     if(Ystart > ((ROW - 1) - FONT_H))
 8     {
 9         Ystart = (Ystart - 1) - FONT_H;
10     }
11 
12     DispOneChar((i >> 12) % 16, Xstart, Ystart, TextColor, BackColor); //ID value
13     DispOneChar((i >> 8) % 16, Xstart + FONT_W, Ystart, TextColor, BackColor);
14     DispOneChar((i >> 4) % 16, Xstart + FONT_W * 2, Ystart, TextColor, BackColor);
15     DispOneChar(i % 16, Xstart + FONT_W * 3, Ystart, TextColor, BackColor);
16 
17     BlockWrite(0, COL - 1, 0, ROW - 1);
18 }
19 void DispStr(unsigned char *str, unsigned int Xstart, unsigned int Ystart, unsigned int TextColor, unsigned int BackColor)
20 {
21     while(!(*str == '\0'))
22     {
23         DispOneChar(ToOrd(*str++), Xstart, Ystart, TextColor, BackColor);
24 
25         if(Xstart > ((COL - 1) - FONT_W))
26         {
27             Xstart = 0;
28             Ystart = Ystart + FONT_H;
29         }
30         else
31         {
32             Xstart = Xstart + FONT_W;
33         }
34 
35         if(Ystart > ((ROW - 1) - FONT_H))
36         {
37             Ystart = 0;
38         }
39     }
40     BlockWrite(0, COL - 1, 0, ROW - 1);
41 }
42 /*
43 绘制一片区域(名字为线,其实可以刷一个面)
44 */
45 void DrawLine(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend, unsigned int color)
46 {
47     unsigned int i, j;
48 
49     BlockWrite(Xstart, Xend, Ystart, Yend);
50 
51     for(i = Ystart; i < Yend + 1; i++)
52     {
53         for(j = Xstart; j < Xend + 1; j++)
54         {
55             WriteOneDot(color);
56         }
57     }
58 }
复制代码

注: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 持续更新中~



本文转自beautifulzzzz博客园博客,原文链接:http://www.cnblogs.com/zjutlitao/p/4995934.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
使用C++开发的web框架dlagon
本项目仅仅是个人的玩具项目, 其中缺陷很多, 问题也很多. 首先整个网络部分是自己看了两三章UNP自己封出来的. 老版本还有一点点错误处理, 新版本完全忽略了错误处理. 另外就是过度设计, 许多的地方没有必要预留变更空间, 我都预留了.
26 0
ndk-build.cmd‘‘ finished with non-zero exit value 2
ndk-build.cmd‘‘ finished with non-zero exit value 2
51 0
Flutter实战(二) 写一个天气查询的APP
前面一篇文章[Flutter实战1 写一个天气查询的APP]实现了一个显示城市、温度、天气、湿度的界面,但是这个界面只有一个显示的功能,没有任何可交互的地方,本篇文章继续完善查询天气的APP的功能。
876 0
C#使用Xamarin开发可移植移动应用进阶篇(8.打包生成安卓APK并精简大小),附源码
原文:C#使用Xamarin开发可移植移动应用进阶篇(8.打包生成安卓APK并精简大小),附源码 前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.
1245 0
《Android App开发入门:使用Android Studio 2.X开发环境》——1-2 在计算机的仿真器上执行 App
本节书摘来自华章计算机《Android App开发入门:使用Android Studio 2.X开发环境》一书中的第1章,第1-2节,作者 施威铭,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1045 0
移动原生App开发和HTML 5开发,你更看好哪个?
小程序的发布,让我们不得不思考,移动原生App开发和HTML 5开发,哪个更有优势? 在技术的发展上,HTML 5会取代App应用吗? 你更看好哪个? 经常会有人问“APP开发究竟是用原生的好点还是H5好点?”   首先我们来看看原生APP,从2010年正式崛起,对开发者而言,不过两三年的时候,对企业而言,更是赖以进入互联网时代的标志,正因如此,不论是隶属于信息服务范畴的IT软硬件开发商或是内容服务商,乃至于一般企业用户,显然都无法抵御这股趋势潮流。
1543 0
Ext树工具类 Jsontree和Xmltree
使用说明:使用本工具类,可以快速从xml和json文件中创建EXT树.预览:tree.html: Ext.BLANK_IMAGE_URL = 'js/ext-2.0/resources/images/default/s.
581 0
858
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载