/*
* 本程序是使用Arduino来驱动“RGB1602 Module For RPI”
* 模块是使用的是IIC总线协议MCP23017芯片扩展的IO来检测按键输入
* 及驱动lcd1602屏幕,RGB三色背光是IO独立控制的。
* 初始化后闪动光标,按不同按键显示不同内容
* 调用了iic总线库"Wire.h"
* IDE环境:Arduino 1.6.5
*/
#include "Wire.h" //调用iic总线库
char inputA = 0x00; //按键输入字符初始化赋值
char outputA = 0x00; //A端口输出字符初始化赋值
char outputB = 0x00; //B端口输出字符初始化赋值
char cache = 0x00; //缓存初始化赋值
char str1[] = "abcdef ABCDEF"; //定义不同字符串
char str2[] = "1234^-M_M-^789";
char str3[] = "Welcome to";
char str4[] = "smilefrog.net";
char str5[] = "Please press";
char str6[] = "the button";
int LCD1602_RS = 7;//LCD1602对应的MCP23017的引脚
int LCD1602_RW = 6;//LCD1602对应的MCP23017的引脚
int LCD1602_EN = 5;//LCD1602对应的MCP23017的引脚
int DB[] = { 1, 2, 3, 4};//LCD1602的数据脚(D7,D6,D5,D4)对应MCP23017的引脚
int r = 6, g = 7, b = 0;//LCD1602的背光控制引脚,r=A6,g=A7,b=B0
int Address = 0x20; //OLED 12864器件7位地址
void key_scan(void) //按键输入函数
{
char input1 = 0x00;
char input2 = 0x00;
Wire.beginTransmission(Address);
Wire.write(0x12); // 设置MCP23017芯片GPIOA的地址
Wire.endTransmission();
Wire.requestFrom(Address, 8); // 读取8位数据
input1 = Wire.read(); // 将读取到的数据赋值到inputA
delay(10);
Wire.beginTransmission(Address);
Wire.write(0x12); // 设置MCP23017芯片GPIOA的地址
Wire.endTransmission();
Wire.requestFrom(Address, 8); // 读取8位数据
input2 = Wire.read(); // 将读取到的数据赋值到inputA
if(input1==input2)
inputA = input2;
}
void writeA(int x, bool y)//芯片GPIOA输出函数
{
switch (x)
{
case 0: cache = 0x01;
break;
case 1: cache = 0x02;
break;
case 2: cache = 0x04;
break;
case 3: cache = 0x08;
break;
case 4: cache = 0x10;
break;
case 5: cache = 0x20;
break;
case 6: cache = 0x40;
break;
case 7: cache = 0x80;
break;
default: break;
}
outputA = (outputA & ~cache) | (y << x);
Wire.beginTransmission(Address);
Wire.write(0x12); // address port A
Wire.write(outputA); // value to send
Wire.endTransmission();
}
void writeB(int x, bool y)//芯片GPIOB输出函数
{
switch (x)
{
case 0: cache = 0x01;
break;
case 1: cache = 0x02;
break;
case 2: cache = 0x04;
break;
case 3: cache = 0x08;
break;
case 4: cache = 0x10;
break;
case 5: cache = 0x20;
break;
case 6: cache = 0x40;
break;
case 7: cache = 0x80;
break;
default: break;
}
outputB = (outputB & ~cache) | (y << x);
Wire.beginTransmission(Address);
Wire.write(0x13); // address port B
Wire.write(outputB); // value to send
Wire.endTransmission();
}
void LCD_Command_Write(char command)//写LCD1602的命令
{
char i, temp;
writeB( LCD1602_RS, 0);
writeB( LCD1602_RW, 0);
temp = command & 0xf0;
for (i = 0; i < 4; i++)
{
writeB(DB[i], (temp << i) & 0x80);
}
writeB( LCD1602_EN, 1);
writeB( LCD1602_EN, 0);
temp = command << 4;
for (i = 0; i < 4; i++)
{
writeB(DB[i], (temp << i) & 0x80);
}
writeB( LCD1602_EN, 1);
writeB( LCD1602_EN, 0);
}
void LCD_Init(void) //LCD1602初始化
{
// delay(50);
LCD_Command_Write(0x28);//4线 2行 5x7
delay(5);
LCD_Command_Write(0x06);//递增
delay(5);
LCD_Command_Write(0x0f);//显示并闪光标0x0 + [1,D(显示),C(开光标),B(光标闪)]
delay(5);
LCD_Command_Write(0x01);// 清屏
delay(5);
/*************诡异的初始化内容,否则显示不正常***************/
LCD_Command_Write(0x83);
LCD_Command_Write(0x80);
LCD_Command_Write(0x82);
LCD_Command_Write(0x83);
/***********************************************************/
LCD_Command_Write(0x01);// 清屏
delay(5);
}
void LCD_Data_Write(char dat)//写LCD1602的数据
{
char i = 0, temp;
writeB( LCD1602_RS, HIGH);
writeB( LCD1602_RW, LOW);
temp = dat;
for (i = 0; i < 4; i++)
{
writeB(DB[i], (temp << i) & 0x80);
}
writeB( LCD1602_EN, HIGH);
writeB( LCD1602_EN, LOW);
temp = dat << 4;
for (i = 0; i < 4; i++)
{
writeB(DB[i], (temp << i) & 0x80);
}
writeB( LCD1602_EN, HIGH);
writeB( LCD1602_EN, LOW);
}
void LCD_SET_XY( int x, int y )//设置显示位置
{
char address;
if (x == 0) address = 0x80 + y;
else if (1 == x) address = 0xC0 + y;
LCD_Command_Write(address);
}
void LCD_Write_Char( int x, int y, char dat)//写字节
{
LCD_SET_XY( x, y );
LCD_Data_Write(dat);
}
void LCD_Write_String(int m, int n, char *s) // 写字符串
{
LCD_SET_XY( m, n ); //设置地址
while (*s) //写字符串
{
LCD_Data_Write(*s);
s ++;
}
}
void setup (void)
{
// Serial.begin(9600);//初始化串口
Wire.begin(); //初始化iic
Wire.beginTransmission(Address);//设置MCP23017芯片GPIOA方向
Wire.write(0x00); // IODIRA register
Wire.write(0x1f); // set port A to ( 0001 1111 )
Wire.endTransmission();
Wire.beginTransmission(Address);//设置MCP23017芯片GPIOA上拉
Wire.write(0x0c); // GPPUA register
Wire.write(0x1f); // set port GPPUA to ( 0001 1111 )
Wire.endTransmission();
writeA(r, 1);//背光闪动
delay(400);
writeA(r, 0);
writeA(g, 1);
delay(400);
writeA(g, 0);
writeB(b, 1);
delay(400);
writeA(r, 1); //消隐
writeA(g, 1);
writeB(b, 1);
Wire.beginTransmission(Address);//设置MCP23017芯片GPIOB为输出
Wire.write(0x01); // IODIRB register
Wire.write(0x00); // set all of port B to outputs
Wire.endTransmission();
LCD_Init();//初始化LCD1602
delay(10);
LCD_Command_Write(0x01);// 清屏
delay(10);
LCD_Write_String(0, 2, str5); //第1行,第1个地址起
LCD_Write_String(1, 0, str6); //第1行,第1个地址起
}
void loop (void)
{
key_scan();
switch (inputA & 0x1f)
{
case 0x1e:
{
writeB(b, 0);
writeA(r, 1);
delay(500);
writeA(r, 0);
writeA(g, 1);
delay(500);
writeA(g, 0);
writeB(b, 1);
delay(500);
writeA(r, 1); //消隐
writeA(g, 1);
writeB(b, 1);
} break;
case 0x1d:
{
LCD_Command_Write(0x01);// 清屏
delay(10);
LCD_Write_String(0, 0, str3); //第1行,第1个地址起
LCD_Write_String(1, 1, str4); //第2行,第2个地址起
} break;
case 0x1b:
{
LCD_Command_Write(0x01);// 清屏
delay(10);
LCD_Write_String(0, 0, str1); //第1行,第1个地址起
LCD_Write_String(1, 1, str2); //第2行,第2个地址起
} break;
case 0x17:
{
LCD_Command_Write(0x01);
delay(10);
LCD_Write_Char(0, 0, 'A'); //第1行,第1个地址
LCD_Write_Char(0, 1, 'a'); //第1行,第2个地址
LCD_Write_Char(0, 2, 'B'); //第1行,第3个地址
LCD_Write_Char(0, 3, 'b'); //第1行,第4个地址
} break;
case 0x0f:
{
LCD_Command_Write(0x01);
delay(10);
LCD_Write_Char(1, 5, 'A'); //第2行,第5个地址
LCD_Write_Char(1, 6, 'a'); //第2行,第7个地址
LCD_Write_Char(1, 7, 'B'); //第2行,第8个地址
LCD_Write_Char(1, 8, 'b'); //第2行,第9个地址
} break;
default: break;
}
}