【原理】从零编写ILI9341驱动全过程(基于Arduino)
最近在淘宝入手了一块ILI9341彩色屏幕,支持320x240分辨率。之前一直很好奇这类单片机驱动的彩色屏幕的原理,就打算自己写一个驱动,从电流层面操控ILI9341屏幕。话不多说,我们开始吧( ̄▽ ̄)~*
1.ILI9341芯片和ILI9341驱动板
首先这里要明确两个概念,ILI9341芯片和ILI9341驱动板。
ILI9341芯片是ilitek发布的液晶驱动芯片,是这个样子的:

而淘宝上的ILI9341驱动板是把ILI9341芯片、屏幕和针脚焊接在一起的电路板,它可能是这个样子的:

也可能是这个样子的:

还可能是这个样子的:

没错,不同的厂家可以制造不同形状,不同接口的ILI9341驱动板,但他们上面都有ILI9341芯片,所以我们可以用相同的方法操作它。
2.如何操作它呢?
这是ILI9341驱动板的背面,我在上面做了些标注,应该会方便理解些。我们只要控制这些针脚的通电与否(高电平与低电平),就能够获得操控这块屏幕的“完整权限”!那这些针脚的定义是什么呢?我们一个一个看:

左上角有五个最重要的针脚,分别是LCD_RST、LCD_CS、LCD_RS、LCD_WR和LCD_RD:(直接用文字写不能冒号对齐,没办法,开个代码框( ̄▽ ̄)~*)
LCD_RST : 即LCD Reset,用于在通电之后复位,初始化整个模块。 LCD_CS : 即LCD Chip Select,用于多个芯片之间的片选操作。由于这块驱动板只有一个可用的芯片,所以一般该针脚不通电。 LCD_RS : 又称D/CX信号线,用于切换写命令(Command)和写数据(Data),当对显示屏写命令(Command)时,应该让针脚不通电,当对显示屏写数据(Data)时,应该让针脚通电。 LCD_WR : 写使能。当LCD_WR不通电,并且LCD_RD通电时,数据传输方向为写入。 LCD_RD : 读使能。
左下角的针脚负责供电,不细讲。
右上角的LCD_D0到LCD_D7是数据脚,通过控制它的通电与否来传输8个比特,也就是8个0或1。这种方式可以传输一个最小值0,最大值255的数字,我们用它来传输所有命令和数据。
右下角的SD_SS,SD_DI,SD_D0,SD_SCK适用于控制SD卡读写的,不属于ILI9341的范畴,我们先不讨论。
那么,如何操作它呢?这张图能够很清楚的说明:(下面用拉低代表示不通电,拉高表示通电,这样术语会更加标准)

- 单片机开机,ILI9341驱动板接收到电流,开始进入待命状态
- 拉低LCD_CS片选信号,选择对ILI9341芯片发送命令
- 通过拉高拉低LCD_D0到LCD_D7数据脚,来表示二进制数据
- 拉低拉高LCD_RS针脚来告诉机器这是一个命令,还是一个数据
- 拉低LCD_WR,进行写使能(可以理解为按下回车键,把LCD_D0到D7的数据发送出去)
这就是发送一个命令或者数据的方法。二进制,十进制和十六进制的转换和表达先直接略过,如果要展开,那可能可以出一本书了( • ̀ω•́ )✧,关于LCD_D0到D7脚应该发送什么,ILITEK在设计ILI9341时就已经规定好了,中文文档在此:
接下来,就是,愉快的,编码时间啦( • ̀ω•́ )✧!!!
3.兼容性设定
不知刚才你有没有注意到数据脚是从LCD_D2开始的?那是因为Arduino Uno开发板的第0和1脚是USB针脚,不能被使用,只能从第2个针脚开始设计:

那我们在编程时要用到LCD_D0和LCD_D1时,就必须写成8和9。另外不同机器脚位也不一样,所以我用宏定义来简化程序:
#define LCD_D0 8 #define LCD_D1 9 #define LCD_D2 2 #define LCD_D3 3 #define LCD_D4 4 #define LCD_D5 5 #define LCD_D6 6 #define LCD_D7 7 #define LCD_RD A0 #define LCD_WR A1 #define LCD_RS A2 #define LCD_CS A3 #define LCD_RST A4
这样即解决了LCD_D0和LCD_D1脚的问题,还搞定的不同开发板的兼容性问题。由于#define是在预编译阶段生成的,所以不会影响代码运行的速度。
4.发送命令和数据
调用这块屏幕的方法很明确,就是写入2进制数字。通过设计厂商提供的命令表发送相应的2进制命令和数据,实现操控。这样做的好处是无论你使用的是什么机器,什么驱动板,只要实现了LcdWriteCommand()和LcdWriteData()两个函数,就可以实现对屏幕的完全控制。
你当然可以用最直接的办法去控制引脚,比如digitalWrite():
void LcdWriteCommand(unsigned char d){
//Write Command Mode On
digitalWrite(LCD_RS,LOW);
//Write Datas to LCD_D0 to LCD_D7
digitalWrite(LCD_D0,d%);
d = d >> ;
digitalWrite(LCD_D1,d%);
d = d >> ;
digitalWrite(LCD_D2,d%);
d = d >> ;
digitalWrite(LCD_D3,d%);
d = d >> ;
digitalWrite(LCD_D4,d%);
d = d >> ;
digitalWrite(LCD_D5,d%);
d = d >> ;
digitalWrite(LCD_D6,d%);
d = d >> ;
digitalWrite(LCD_D7,d%);
d = d >> ;
//Enable Datas
digitalWrite(LCD_WR,LOW);
digitalWrite(LCD_WR,HIGH);
}
void LcdWriteData(unsigned char d){
//Write Data Mode On
digitalWrite(LCD_RS,HIGH);
//Write Datas to LCD_D0 to LCD_D7
digitalWrite(LCD_D0,d%);
d = d >> ;
digitalWrite(LCD_D1,d%);
d = d >> ;
digitalWrite(LCD_D2,d%);
d = d >> ;
digitalWrite(LCD_D3,d%);
d = d >> ;
digitalWrite(LCD_D4,d%);
d = d >> ;
digitalWrite(LCD_D5,d%);
d = d >> ;
digitalWrite(LCD_D6,d%);
d = d >> ;
digitalWrite(LCD_D7,d%);
d = d >> ;
//Enable Datas
digitalWrite(LCD_WR,LOW);
digitalWrite(LCD_WR,HIGH);
}
但是这样做的话,速度嘛。。。看看这个,你就不会想用digitalWrite了:

单片机中,速度为王,我们还是直接改Register吧:
void LcdWriteCommand(unsigned char d){
//Write Command Mode On
fastDigitalWriteLOW(LCD_RS);
//Write Datas to LCD_D0 to LCD_D7
PORTD = (PORTD & B00000011) | ((d) & B11111100);
PORTB = (PORTB & B11111100) | ((d) & B00000011);
//Enable Datas
fastDigitalWriteLOW(LCD_WR);
fastDigitalWriteHIGH(LCD_WR);
}
void LcdWriteData(unsigned char d){
//Write Command Mode On
fastDigitalWriteHIGH(LCD_RS);
//Write Datas to LCD_D0 to LCD_D7
PORTD = (PORTD & B00000011) | ((d) & B11111100);
PORTB = (PORTB & B11111100) | ((d) & B00000011);
//Enable Datas
fastDigitalWriteLOW(LCD_WR);
fastDigitalWriteHIGH(LCD_WR);
}
这段代码中,我用了宏定义来实现fastDigitalWriteHIGH()和fastDigitalWriteLOW(),这两个定义能避免函数的栈调用。其实用内联函数来写也可以实现:
inline void fastDigitalWriteHIGH(int Pin){
*(portOutputRegister(digitalPinToPort(Pin)))|=digitalPinToBitMask(Pin);
return;
}
但我就是喜欢宏定义,而且宏定义行数少些。
另外你可能会疑惑:什么是PORTB和PORTD?
PORTB其实就是针脚8-13,PORTD其实就是针脚0-7:

假如你有一个这样的二进制数:
把他转换成十进制:
再把它赋值给PORTD
PORTD = ;
你就会发现针脚2通电了(图中连接到左边第一个红色灯泡):

这就是PORTD的真正意义,它使用一个从0到255的数,记录针脚0到7的通电情况。
那我们为什么不用digitalWrite(),而是要用PORTB和PORTD呢?因为快啊( ̄▽ ̄)~*
5.Enjoy!
我们刚刚实现了LcdWriteCommand()和LcdWriteData()两个函数,现在,我们就可以实现对屏幕的完全控制了!
首先,先运行一段初始化命令:
//Initialize Data Pins pinMode(LCD_D0,OUTPUT); pinMode(LCD_D1,OUTPUT); pinMode(LCD_D2,OUTPUT); pinMode(LCD_D3,OUTPUT); pinMode(LCD_D4,OUTPUT); pinMode(LCD_D5,OUTPUT); pinMode(LCD_D6,OUTPUT); pinMode(LCD_D7,OUTPUT); //Initialize Command Pins pinMode(LCD_RD,OUTPUT); pinMode(LCD_WR,OUTPUT); pinMode(LCD_RS,OUTPUT); pinMode(LCD_CS,OUTPUT); pinMode(LCD_RST,OUTPUT); digitalWrite(LCD_CS,LOW); digitalWrite(LCD_RD,HIGH); digitalWrite(LCD_WR,LOW); //Reset digitalWrite(LCD_RST,HIGH); delay(); digitalWrite(LCD_RST,LOW); delay(); digitalWrite(LCD_RST,HIGH); delay(); LcdWriteCommand(0xCB); LcdWriteData(0x39); LcdWriteData(0x2C); LcdWriteData(0x00); LcdWriteData(0x34); LcdWriteData(0x02); LcdWriteCommand(0xCF); LcdWriteData(0x00); LcdWriteData(0XC1); LcdWriteData(0X30); LcdWriteCommand(0xE8); LcdWriteData(0x85); LcdWriteData(0x00); LcdWriteData(0x78); LcdWriteCommand(0xEA); LcdWriteData(0x00); LcdWriteData(0x00); LcdWriteCommand(0xED); LcdWriteData(0x64); LcdWriteData(0x03); LcdWriteData(0X12); LcdWriteData(0X81); LcdWriteCommand(0xF7); LcdWriteData(0x20); LcdWriteCommand(0xC0); //Power control LcdWriteData(0x23); //VRH[5:0] LcdWriteCommand(0xC1); //Power control LcdWriteData(0x10); //SAP[2:0];BT[3:0] LcdWriteCommand(0xC5); //VCM control LcdWriteData(0x3e); //Contrast LcdWriteData(0x28); LcdWriteCommand(0xC7); //VCM control2 LcdWriteData(0x86); //-- LcdWriteCommand(0x36); // Memory Access Control LcdWriteData(0x48); LcdWriteCommand(0x3A); LcdWriteData(0x55); LcdWriteCommand(0xB1); LcdWriteData(0x00); LcdWriteData(0x18); LcdWriteCommand(0xB6); // Display Function Control LcdWriteData(0x08); LcdWriteData(0x82); LcdWriteData(0x27); LcdWriteCommand(0x11); //Exit Sleep delay(); LcdWriteCommand(0x29); //Display on LcdWriteCommand(0x2c);
这么多!不要怕,原样复制过去运行就好。这段命令是按照ILITEK设计文档中的规则发送的,用于初始化屏幕。运行完这段命令之后,我们就可以开始发自己的命令了。
我们试着来清一下屏。清屏就是指定一块区域,然后给屏幕每一个像素点的颜色为白色,这样就好了。
首先定义我们要写入的区域,这里就是从(0,0)写入到(239,319):
; ; ; ;
接着通知屏幕我们要写入的区域的X坐标的起始、终止位置(命令0x2a):
LcdWriteCommand(0x2a);
然后发送X坐标的起始位置(x1),和X坐标的终止位置(x2)。我们的机器一次只能发送八位数字,但八位数字最大只能表示255,所以我们要分两次发送,先发送前八位,再发送后八位:
LcdWriteData(x1>>); LcdWriteData(x1); LcdWriteData(x2>>); LcdWriteData(x2);
Y坐标也是一样,只是把通知命令改成0x2b:
LcdWriteCommand(0x2b); LcdWriteData(y1>>); LcdWriteData(y1); LcdWriteData(y2>>); LcdWriteData(y2);
接着,我们发送开始写入的命令(0x2c),告诉屏幕我要开始发送像素了:
LcdWriteCommand(0x2c);
最后,发送所有像素的颜色数据(Data)。里面的RGB()宏定义是我在上一篇文章实现的。另外,因为是数据,所以我们要使用LcdWriteData():
#define RGB(r,g,b) ((b&31)+((g&63)<<5)+((r&31)<<11))
for(int i=y1;i<=y2;i++){
for(int j=x1;j<=x2;j++){
LcdWriteData(RGB(,,)>>);
LcdWriteData(RGB(,,));
}
}
保存,下载。


刷屏完整代码:
// Breakout/Arduino UNO pin usage:
// LCD Data Bit : 7 6 5 4 3 2 1 0
// Uno dig. pin : 7 6 5 4 3 2 9 8
// Uno port/pin : PD7 PD6 PD5 PD4 PD3 PD2 PB1 PB0
// Mega dig. pin: 29 28 27 26 25 24 23 22
#define LCD_D0 8
#define LCD_D1 9
#define LCD_D2 2
#define LCD_D3 3
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7
#define LCD_RD A0
#define LCD_WR A1
#define LCD_RS A2
#define LCD_CS A3
#define LCD_RST A4
#define fastDigitalWriteHIGH(Pin) *(portOutputRegister(digitalPinToPort(Pin)))|=digitalPinToBitMask(Pin) //Faster digitalWrite(Pin,HIGH);
#define fastDigitalWriteLOW(Pin) *(portOutputRegister(digitalPinToPort(Pin)))&=~digitalPinToBitMask(Pin) //Faster digitalWrite(Pin,LOW);
#define RGB(r,g,b) ((b&31)+((g&63)<<5)+((r&31)<<11))
void LcdWriteCommand(unsigned char d){
//Write Command Mode On
fastDigitalWriteLOW(LCD_RS);
//Write Datas to LCD_D0 to LCD_D7
PORTD = (PORTD & B00000011) | ((d) & B11111100);
PORTB = (PORTB & B11111100) | ((d) & B00000011);
//Enable Datas
fastDigitalWriteLOW(LCD_WR);
fastDigitalWriteHIGH(LCD_WR);
}
void LcdWriteData(unsigned char d){
//Write Command Mode On
fastDigitalWriteHIGH(LCD_RS);
//Write Datas to LCD_D0 to LCD_D7
PORTD = (PORTD & B00000011) | ((d) & B11111100);
PORTB = (PORTB & B11111100) | ((d) & B00000011);
//Enable Datas
fastDigitalWriteLOW(LCD_WR);
fastDigitalWriteHIGH(LCD_WR);
}
void setup(){
//Initialize Data Pins
pinMode(LCD_D0,OUTPUT);
pinMode(LCD_D1,OUTPUT);
pinMode(LCD_D2,OUTPUT);
pinMode(LCD_D3,OUTPUT);
pinMode(LCD_D4,OUTPUT);
pinMode(LCD_D5,OUTPUT);
pinMode(LCD_D6,OUTPUT);
pinMode(LCD_D7,OUTPUT);
//Initialize Command Pins
pinMode(LCD_RD,OUTPUT);
pinMode(LCD_WR,OUTPUT);
pinMode(LCD_RS,OUTPUT);
pinMode(LCD_CS,OUTPUT);
pinMode(LCD_RST,OUTPUT);
digitalWrite(LCD_CS,LOW);
digitalWrite(LCD_RD,HIGH);
digitalWrite(LCD_WR,LOW);
//Reset
digitalWrite(LCD_RST,HIGH);
delay();
digitalWrite(LCD_RST,LOW);
delay();
digitalWrite(LCD_RST,HIGH);
delay();
LcdWriteCommand(0xCB);
LcdWriteData(0x39);
LcdWriteData(0x2C);
LcdWriteData(0x00);
LcdWriteData(0x34);
LcdWriteData(0x02);
LcdWriteCommand(0xCF);
LcdWriteData(0x00);
LcdWriteData(0XC1);
LcdWriteData(0X30);
LcdWriteCommand(0xE8);
LcdWriteData(0x85);
LcdWriteData(0x00);
LcdWriteData(0x78);
LcdWriteCommand(0xEA);
LcdWriteData(0x00);
LcdWriteData(0x00);
LcdWriteCommand(0xED);
LcdWriteData(0x64);
LcdWriteData(0x03);
LcdWriteData(0X12);
LcdWriteData(0X81);
LcdWriteCommand(0xF7);
LcdWriteData(0x20);
LcdWriteCommand(0xC0); //Power control
LcdWriteData(0x23); //VRH[5:0]
LcdWriteCommand(0xC1); //Power control
LcdWriteData(0x10); //SAP[2:0];BT[3:0]
LcdWriteCommand(0xC5); //VCM control
LcdWriteData(0x3e); //Contrast
LcdWriteData(0x28);
LcdWriteCommand(0xC7); //VCM control2
LcdWriteData(0x86); //--
LcdWriteCommand(0x36); // Memory Access Control
LcdWriteData(0x48);
LcdWriteCommand(0x3A);
LcdWriteData(0x55);
LcdWriteCommand(0xB1);
LcdWriteData(0x00);
LcdWriteData(0x18);
LcdWriteCommand(0xB6); // Display Function Control
LcdWriteData(0x08);
LcdWriteData(0x82);
LcdWriteData(0x27);
LcdWriteCommand(0x11); //Exit Sleep
delay();
LcdWriteCommand(0x29); //Display on
LcdWriteCommand(0x2c);
//Set Writing Area
;
;
;
;
LcdWriteCommand(0x2a);
LcdWriteData(x1>>);
LcdWriteData(x1);
LcdWriteData(x2>>);
LcdWriteData(x2);
LcdWriteCommand(0x2b);
LcdWriteData(y1>>);
LcdWriteData(y1);
LcdWriteData(y2>>);
LcdWriteData(y2);
//Start Writing
LcdWriteCommand(0x2c);
for(int i=y1;i<=y2;i++){
for(int j=x1;j<=x2;j++){
LcdWriteData(RGB(,,)>>);
LcdWriteData(RGB(,,));
}
}
}
void loop(){
}
接下来的路线就很简单了,把指定区域的命令(0x2a,0x2b,0x2c)分装成LcdOpenWindow()函数,再实现LcdFill()函数,一个完整的ILI9341驱动就完成了:
#define LCD_D0 8
#define LCD_D1 9
#define LCD_D2 2
#define LCD_D3 3
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7
#define LCD_RD A0
#define LCD_WR A1
#define LCD_RS A2
#define LCD_CS A3
#define LCD_RST A4
#define fastDigitalWriteHIGH(Pin) *(portOutputRegister(digitalPinToPort(Pin)))|=digitalPinToBitMask(Pin) //Faster digitalWrite(Pin,HIGH);
#define fastDigitalWriteLOW(Pin) *(portOutputRegister(digitalPinToPort(Pin)))&=~digitalPinToBitMask(Pin) //Faster digitalWrite(Pin,LOW);
#define RGB(r,g,b) ((b&31)+((g&63)<<5)+((r&31)<<11))
void LcdWriteCommand(unsigned char d){
//Write Command Mode On
fastDigitalWriteLOW(LCD_RS);
//Write Datas to LCD_D0 to LCD_D7
PORTD = (PORTD & B00000011) | ((d) & B11111100);
PORTB = (PORTB & B11111100) | ((d) & B00000011);
//Enable Datas
fastDigitalWriteLOW(LCD_WR);
fastDigitalWriteHIGH(LCD_WR);
}
void LcdWriteData(unsigned char d){
//Write Command Mode On
fastDigitalWriteHIGH(LCD_RS);
//Write Datas to LCD_D0 to LCD_D7
PORTD = (PORTD & B00000011) | ((d) & B11111100);
PORTB = (PORTB & B11111100) | ((d) & B00000011);
//Enable Datas
fastDigitalWriteLOW(LCD_WR);
fastDigitalWriteHIGH(LCD_WR);
}
void LcdInit(void){
//Initialize Data Pins
pinMode(LCD_D0,OUTPUT);
pinMode(LCD_D1,OUTPUT);
pinMode(LCD_D2,OUTPUT);
pinMode(LCD_D3,OUTPUT);
pinMode(LCD_D4,OUTPUT);
pinMode(LCD_D5,OUTPUT);
pinMode(LCD_D6,OUTPUT);
pinMode(LCD_D7,OUTPUT);
//Initialize Command Pins
pinMode(LCD_RD,OUTPUT);
pinMode(LCD_WR,OUTPUT);
pinMode(LCD_RS,OUTPUT);
pinMode(LCD_CS,OUTPUT);
pinMode(LCD_RST,OUTPUT);
digitalWrite(LCD_CS,LOW);
digitalWrite(LCD_RD,HIGH);
digitalWrite(LCD_WR,LOW);
//Reset
digitalWrite(LCD_RST,HIGH);
delay();
digitalWrite(LCD_RST,LOW);
delay();
digitalWrite(LCD_RST,HIGH);
delay();
LcdWriteCommand(0xCB);
LcdWriteData(0x39);
LcdWriteData(0x2C);
LcdWriteData(0x00);
LcdWriteData(0x34);
LcdWriteData(0x02);
LcdWriteCommand(0xCF);
LcdWriteData(0x00);
LcdWriteData(0XC1);
LcdWriteData(0X30);
LcdWriteCommand(0xE8);
LcdWriteData(0x85);
LcdWriteData(0x00);
LcdWriteData(0x78);
LcdWriteCommand(0xEA);
LcdWriteData(0x00);
LcdWriteData(0x00);
LcdWriteCommand(0xED);
LcdWriteData(0x64);
LcdWriteData(0x03);
LcdWriteData(0X12);
LcdWriteData(0X81);
LcdWriteCommand(0xF7);
LcdWriteData(0x20);
LcdWriteCommand(0xC0); //Power control
LcdWriteData(0x23); //VRH[5:0]
LcdWriteCommand(0xC1); //Power control
LcdWriteData(0x10); //SAP[2:0];BT[3:0]
LcdWriteCommand(0xC5); //VCM control
LcdWriteData(0x3e); //Contrast
LcdWriteData(0x28);
LcdWriteCommand(0xC7); //VCM control2
LcdWriteData(0x86); //--
LcdWriteCommand(0x36); // Memory Access Control
LcdWriteData(0x48);
LcdWriteCommand(0x3A);
LcdWriteData(0x55);
LcdWriteCommand(0xB1);
LcdWriteData(0x00);
LcdWriteData(0x18);
LcdWriteCommand(0xB6); // Display Function Control
LcdWriteData(0x08);
LcdWriteData(0x82);
LcdWriteData(0x27);
LcdWriteCommand(0x11); //Exit Sleep
delay();
LcdWriteCommand(0x29); //Display on
LcdWriteCommand(0x2c);
}
void LcdOpenWindow(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2){
LcdWriteCommand(0x2a);
LcdWriteData(x1>>);
LcdWriteData(x1);
LcdWriteData(x2>>);
LcdWriteData(x2);
LcdWriteCommand(0x2b);
LcdWriteData(y1>>);
LcdWriteData(y1);
LcdWriteData(y2>>);
LcdWriteData(y2);
LcdWriteCommand(0x2c);
}
void LcdFill(int x,int y,int width,int height,unsigned int color)
{
LcdOpenWindow(x,y,x+width-,y+height-);
for(int i=y;i<y+height;i++){
for(int j=x;j<x+width;j++){
LcdWriteData(color>>);
LcdWriteData(color);
}
}
}
void setup(){
LcdInit();
LcdFill(,,,,RGB(,,));
LcdFill(,,,,RGB(,,));
LcdFill(,,,,RGB(,,));
LcdFill(,,,,RGB(,,));
}
void loop(){
}

都看到这了,还不点个赞吗?(✪ω✪)
【原理】从零编写ILI9341驱动全过程(基于Arduino)的更多相关文章
- CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL
CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL +BIT祝威+悄悄在此留下版了个权的信息说: 开始 本文用step by step的方式,讲述如何使 ...
- uboot的GPIO驱动分析--基于全志的A10芯片【转】
本文转载自:http://blog.csdn.net/lw2011cg/article/details/68954707 uboot的GPIO驱动分析--基于全志的A10芯片 转载至:http://b ...
- 基于arduino的红外传感系统
一.作品背景 在这个科技飞速发展的时代,物联网已经成为了我们身边必不可少的技术模块,我这次课程设计做的是一个基于arduino+树莓派+OneNet的红外报警系统,它主要通过识别人或者动物的运动来判断 ...
- 基于 Arduino 开发板,这款插座是可编程且开源的
基于 Arduino 开发板,这款插座是可编程且开源的 https://www.oschina.net/news/74861/open-source-socket https://github.com ...
- 简析LCD1602液晶驱动及在Arduino上的实例实现
这几日在倒腾新到的Arduino,比起普通单片机来,感觉写程序太简单了.不过和外设打交道还是没那么容易,比如今天要说的看似简单的LCD1602液晶,却费了我一整天才基本搞懂,不过还是有一个小问题没有实 ...
- 基于Arduino开发的智能蓝牙小车
基于Arduino的智能蓝牙小车 材料准备: Arduino开发板一块.四驱小车底板及相关配件一套.L298N驱动模块一个.HC-05/06蓝牙模块一块,九伏电源一块(用于主板供电).12V锂电池一块 ...
- 基于arduino的气象站
bmp180的简介: • 压力范围:~1100hPa(海拔 米~- 米) • 电源电压:.8V~.6V(VDDA), .62V~.6V(VDDD) • 尺寸:.6mmx3.8x0.93mm • 低功耗 ...
- linux驱动开发—基于Device tree机制的驱动编写
前言Device Tree是一种用来描述硬件的数据结构,类似板级描述语言,起源于OpenFirmware(OF).在目前广泛使用的Linux kernel 2.6.x版本中,对于不同平台.不同硬件,往 ...
- 手把手教你从零实现Linux misc设备驱动一(基于友善之臂4412开发板)
关于怎样来写一个misc设备,在前面有篇文章已经介绍了大致的流程,如今就让我们来实现一个最简单的misc设备驱动. http://blog.csdn.net/morixinguan/article/d ...
随机推荐
- idea各种中文显示乱码解决大全
本文链接:https://blog.csdn.net/liqimo1799/article/details/81811153中文乱码问题分类: 编码普通中文乱码properties文件中文乱码cons ...
- HDU2087 剪花布条 题解 KMP算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题目大意:给定字符串 \(s\) 和 \(t\) ,找出 \(s\) 中出现不重叠的 \(t\) ...
- cp拷贝
1 cp 拷贝.复制 NAME cp - copy files and directories SYNOPSIS cp [OPTION]... [-T] SOURCE DEST -- c ...
- Python--day23--初识面向对象复习
面向对象编程是大程序编程思想:
- java 创建线程方式
1.继承Thread类 子类覆写父类中的run方法,将线程运行的代码存放在run中. 建立子类对象的同时线程也被创建. 通过调用start方法开启线程. 2.实现Runnable接口 子类覆盖接口中的 ...
- 添加gitignore文件后使其生效
https://www.cnblogs.com/AliliWl/p/7880243.html 遇到的问题 我们发现在添加.gitignore文件后,当我们想push文件的时候,我们声明的忽略文件还是会 ...
- 整理了一下angularJs的webpack模板
github地址:https://github.com/qianxiaoning/demo-angularJs1.7.5 欢迎大家star或者fork呀~ 目录结构 src/ components/ ...
- Django入门10--admin增强
- java 综合示例代码
package javaenhance.src.cn.itcast.day3; import java.lang.reflect.Constructor; import java.lang.refle ...
- P1044 最大值最小化
题目描述 在印刷术发明之前,复制一本书是一个很困难的工作,工作量很大,而且需要大家的积极配合来抄写一本书,团队合作能力很重要.当时都是通过招募抄写员来进行书本的录入和复制工作的, 假设现在要抄写 \( ...