FriendlyARM官方已经提供了GPIO驱动库,只需要下载-编译即可使用。
GPIO
NanoPi M1 Plus GPIO wiki链接
可以看出Pi提供的接口还是比较丰富的,我将要使用其中4个GPIO点亮一个彩色OLED屏。
WiringPi安装
wiringPi库最早是由Gordon Henderson所编写并维护的一个用C语言写成的类库,除了GPIO库,还包括了I2C库、SPI库、UART库和软件PWM库等,由于wiringPi的API函数和arduino非常相似,这也使得它广受欢迎。
wiringPi库除了提供wiringPi类库及其头文件外,还提供了一个命令行工具gpio:可以用来设置和读写GPIO管脚,以方便在Shell脚本中控制GPIO管脚。
wiringPi的安装非常简单,使用默认软件源安装速度还是比较快的,不需要换源。
指令
git clone https://github.com/friendlyarm/WiringNP
cd WiringNP/
git checkout nanopi-m1
chmod 755 build
./build
编写C文件并编译
操作系统内置了gcc,可以快速开始编译而不需要安装编译器, 通过gcc -v
命令查看版本信息。
通过vim编译器编辑C文件(下图中使用的vi,实测vim在操作系统中是安装了的,可以直接使用vim命令)。
- 创建C文件
指令
pi@NanoPi-M1-Plus:~$ touch MyFirstCode.c | touch 用于创建文件
pi@NanoPi-M1-Plus:~$ ls -l | ls 用于查看文件及目录,-l是指令选项:以列表形式显示
total 8 |
drwxrwxr-x 3 pi pi 4096 Nov 25 07:33 C_Language |
-rw-rw-r-- 1 pi pi 0 Nov 28 14:11 MyFirstCode.c | 刚刚创建的文件
drwxrwxr-x 8 pi pi 4096 Nov 25 07:02 WiringNP |
- 编辑
pi@NanoPi-M1-Plus:~$ vim MyFirstCode.c | vim 使用VIM编辑目标C文件,执行后进入VIM界面
进入VIM的默认界面
VIM是一种命令行模式下的编辑器,其逻辑不同于图形界面下的编辑器,特征为:鼠标基本没用,提供很多指令,三种运行模式(插入/编辑模式、命令模式、底行命令模式),其用法多变,可操作性、可拓展性极强,但是新手上手难。
对于VIM的教学视频网上很多,这里给个链接:VIM教学视频
光VIM的用法就够写个几章,目前我也是刚学会一点,就不在这写了。
单个文件编译没有问题,接下来就要编译OLED驱动了。
OLED驱动
- 创建工作目录
- 创建4个文件
test.c 测试文件
oled.c 驱动文件
oled.h 驱动文件
font.h 字体库 - 编译
- 运行
Linux运行界面
实际效果
驱动源码
/**
* @file oled.h
* @brief OLED驱动头文件
* @date 2020/11/28
* @note 调用oled驱动只需要包含此文件即可
*/
#ifndef __OLED_H
#define __OLED_H
/* Include Files ----------------------------------------*/
#include <wiringPi.h>
#include <stdint.h>
/* Golbal Defines ---------------------------------------*/
#define LCD_W 240
#define LCD_H 240
#define SIZE 16
#define XLevelL 0x00
#define XLevelH 0x10
#define Max_Column 128
#define Max_Row 64
#define Brightness 0xFF
#define X_WIDTH 128
#define Y_WIDTH 64
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40
#define BRRED 0XFC07
#define GRAY 0X8430
//GUI颜色
#define DARKBLUE 0X01CF
#define LIGHTBLUE 0X7D7C
#define GRAYBLUE 0X5458
//以上三色为PANEL的颜色
#define LIGHTGREEN 0X841F //浅绿色
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
/* GPIO Defines -----------------------------------------*/
#define OLED_SCLK_Clr() digitalWrite(11,LOW)
#define OLED_SCLK_Set() digitalWrite(11,HIGH)
#define OLED_SDIN_Clr() digitalWrite(5,LOW)
#define OLED_SDIN_Set() digitalWrite(5,HIGH)
#define OLED_RST_Clr() digitalWrite(4,LOW)
#define OLED_RST_Set() digitalWrite(4,HIGH)
#define OLED_DC_Clr() digitalWrite(1,LOW)
#define OLED_DC_Set() digitalWrite(1,HIGH)
#define OLED_BLK_Clr() digitalWrite(21,LOW)
#define OLED_BLK_Set() digitalWrite(21,LOW)
/* Global Variables -------------------------------------*/
extern uint16_t BACK_COLOR; ///< Background
extern uint16_t POINT_COLOR; ///< Draw Piont
void LCD_Writ_Bus(char dat); ///< 串行写入
void LCD_WR_DATA8(char da); ///< 8bit写入
void LCD_WR_DATA(int da); ///< 16bit写入
void LCD_WR_REG(char da); ///< 寄存器
void LCD_WR_REG_DATA(int reg, int da); ///< 寄存器写入
void Address_set(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2); ///< 地址设置
/** 初始化函数 */
void LCD_Init(void);
/**
* @brief 清屏函数
* @param Color: 清屏填充色
*/
void LCD_Clear(uint16_t Color);
/**
* @brief 在指定区域内填充指定颜色
* @note 区域大小:(xend-xsta)*(yend-ysta)
*/
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color);
/**
* @brief 画点
*/
void LCD_DrawPoint(uint16_t x, uint16_t y);
/**
* @brief 画一个大点
*/
void LCD_DrawPoint_big(uint16_t x, uint16_t y);
/**
* @brief 画线
* @param x1,y1: 起点坐标
* @param x2,y2: 终点坐标
*/
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
/** 画矩形 */
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
/**
* @brief 在指定位置画一个指定大小的圆
* @param x , y: 中心点
* @param r: 半径
*/
void Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r);
/**
* @brief 在指定位置显示一个字符
* @param num : 要显示的字符:" "--->"~"
* @param mode: 叠加方式(1)还是非叠加方式(0)
* @note 在指定位置显示一个字符
*/
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint8_t mode);
/** m^n函数 */
uint32_t mypow(uint8_t m, uint8_t n);
/**
* @brief 显示数字
* @param x , y: 起点坐标
* @param len : 数字的位数
* @param color: 颜色
* @param num : 数值(0~4294967295);
*/
void LCD_ShowNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len);
/**
* @brief 显示字符串
* @param x,y:起点坐标
* @param p:字符串起始地址
* @note 用16字体
*/
void LCD_ShowString(uint16_t x, uint16_t y, const uint8_t *p);
#endif
/**
* @file oled.c
* @brief oled驱动C文件
*/
#include "oled.h"
#include "font.h"
uint16_t BACK_COLOR = BLACK; //Background
uint16_t POINT_COLOR = RED; //Draw Piont
void LCD_Writ_Bus(char dat) //串行数据写入
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_SCLK_Clr();
if (dat & 0x80)
OLED_SDIN_Set();
else
OLED_SDIN_Clr();
OLED_SCLK_Set();
dat <<= 1;
}
}
void LCD_WR_DATA8(char da) //发送数据-8位参数
{
//OLED_CS_Clr();
OLED_DC_Set();
LCD_Writ_Bus(da);
// OLED_CS_Set();
}
void LCD_WR_DATA(int da)
{
// OLED_CS_Clr();
OLED_DC_Set();
LCD_Writ_Bus(da >> 8);
LCD_Writ_Bus(da);
// OLED_CS_Set();
}
void LCD_WR_REG(char da)
{
// OLED_CS_Clr();
OLED_DC_Clr();
LCD_Writ_Bus(da);
// OLED_CS_Set();
}
void LCD_WR_REG_DATA(int reg, int da)
{
// OLED_CS_Clr();
LCD_WR_REG(reg);
LCD_WR_DATA(da);
// OLED_CS_Set();
}
void Address_set(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
{
LCD_WR_REG(0x2a);
LCD_WR_DATA8(x1 >> 8);
LCD_WR_DATA8(x1);
LCD_WR_DATA8(x2 >> 8);
LCD_WR_DATA8(x2);
LCD_WR_REG(0x2b);
LCD_WR_DATA8(y1 >> 8);
LCD_WR_DATA8(y1);
LCD_WR_DATA8(y2 >> 8);
LCD_WR_DATA8(y2);
LCD_WR_REG(0x2C);
}
void LCD_Init(void)
{
pinMode(1, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(11, OUTPUT);
// OLED_CS_Clr(); //打开片选使能
OLED_RST_Clr();
delay(200);
OLED_RST_Set();
delay(200);
OLED_BLK_Set();
//************* Start Initial Sequence **********//
LCD_WR_REG(0x36);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xB7);
LCD_WR_DATA8(0x35);
LCD_WR_REG(0xBB);
LCD_WR_DATA8(0x19);
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x2C);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x12);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0xC6);
LCD_WR_DATA8(0x0F);
LCD_WR_REG(0xD0);
LCD_WR_DATA8(0xA4);
LCD_WR_DATA8(0xA1);
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x2B);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x54);
LCD_WR_DATA8(0x4C);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x0B);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x23);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x44