树莓派开发笔记06-树莓派的SPI控制(点亮0.96OLED)

news2024/12/23 23:39:29

实验说明

我们这里会使用SPI去驱动一个0.96的OLED,首先需要打开SPI

sudo raspi-config
Interfacing Options------>SPI------>Yes------->OK------->finsh

然后将屏幕接到树莓派上,接mosi和sclk的脚,DC接28,RST接29,CE接CE0

这个实验有一个坑我还没找到,就是每次我使用了BCM库来控制屏幕后,就不能使用Python和WringPi来控制了,这时候把SPI关一次再开一次才可以使用,但是如果一个时间内只掉用他们中的单独一个,是不会有问题的。

在这里插入图片描述

代码编写

wiringPi

主要说一下怎么初始化和发送数据,具体的实现,参考开源链接。

1、选择SPI的通道和速度。

channel只有0和1这两个值,表示初始化哪个SPI通道;

speed的范围是500000 到32000000,这个是SPI通讯的速度范围,单位是Hz;

int wiringPiSPISetup     (int channel, int speed) ;

2、开始数据传输

channel只有0和1这两个值,表示初始化哪个SPI通道;
data要传输的字节,十六进制;
len传输的字节长度。

int wiringPiSPIDataRW    (int channel, unsigned char *data, int len) ;

下面是一个初始化SPI的代码,然后使用的OLED.c就是中景元开源的代码,将SPI部分做了修改。

这是main.c的代码

#include <wiringPi.h>
#include <stdio.h>
#include <wiringPiI2C.h>
#include "oled.h"
#include <wiringPiSPI.h>

#define LCD_DC  28     // 模式选择 1:写数据 0:写命令
#define LCD_DIN 12     // 串行数据线
#define LCD_CLK 14     // 串行时钟线
#define LCD_RST 29     // 复位信号  低电平有效
#define LCD_CE  10     // 芯片使能  低电平有效

#define SPI_CHANNEL 0

void oled_write_one_byte(uint8_t dat,uint8_t mode)
{ 
    digitalWrite(LCD_CE,LOW);
    if (mode == OLED_DATA) { // 写数据
        digitalWrite(LCD_DC,HIGH);
    }
    else { // 写命令
        digitalWrite(LCD_DC,LOW);
    }
    uint8_t *tempData = &dat;
    wiringPiSPIDataRW(SPI_CHANNEL, tempData, 1);
    digitalWrite (LCD_CE, HIGH);
}

void set_rst_level(uint8_t level)
{
    if(level == 1)
    {
        digitalWrite(LCD_RST,HIGH);
    }else
    {
        digitalWrite(LCD_RST,LOW);
    }
}

void delay_ms(uint8_t ms)
{
    delay(ms);
}

int main(void)
{ 
    if(wiringPiSetup() < 0) //当使用这个函数初始化树莓派引脚时,程序使用的是wiringPi 引脚编号表。
        return 1;

    pinMode(LCD_DC,OUTPUT);
    pinMode(LCD_RST,OUTPUT);
    pinMode(LCD_CE,OUTPUT);

    int isOK = wiringPiSPISetup(SPI_CHANNEL, 1000000);
    if (isOK == -1) {
        printf("SPI设置失败\n");
    }
    else {
        printf("SPI设置OK == %d\n",isOK);
    }
 
    OLED_Init();
    OLED_Clear();
    OLED_ShowString(0,0,(char*)"HELLO2",16,1);
    OLED_Refresh();//更新显示
 
    return 0;
}

这是oled.c主要修改的部分

extern void oled_write_one_byte(uint8_t dat,uint8_t mode);
extern void set_rst_level(uint8_t level);
extern void delay_ms(uint8_t ms);

void OLED_WR_Byte(uint8_t dat,uint8_t mode)
{
    oled_write_one_byte(dat,mode);
}

void OLED_RST_SET(uint8_t level)
{
    set_rst_level(level);
}

void LCD_DELAY_MS(uint8_t ms)
{
    delay_ms(ms);
}

//OLED的初始化
void OLED_Init(void)
{
    OLED_RST_SET(0); // 液晶复位
    LCD_DELAY_MS(20);
    OLED_RST_SET(1);
    LCD_DELAY_MS(20);
    ...
}

然后编译这段代码

cc -Wall -o main main.c oled.c -lwiringPi

-Wall 表示编译时显示所有警告,-lwiringPi 表示编译时动态加载 wiringPi 库

编译完成后调用生成的main文件

sudo ./main

想要停止这个程序,Ctrl+c即可。

bcm2835

主要说一下怎么初始化和发送数据,具体的实现,参考开源链接。

1、开始SPI操作

int bcm2835_i2c_begin(void);

2、设置高位在前还是低位在前

void bcm2835_spi_setBitOrder(uint8_t order);

3、设置工作模式

void bcm2835_spi_setDataMode(uint8_t mode);

4、设置分频系数

void bcm2835_spi_setClockDivider(uint16_t divider);

5、选择控制哪个CS

void bcm2835_spi_chipSelect(uint8_t cs);

6、选择激活时的CS电平,就是工作时候的CS电平

void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active);

7、结束SPI的操作

void bcm2835_spi_end(void);

注意,下面是一个实际例子,oled部分的处理和wiringPi一样这里就不写了。注意两种库的引脚编号不一样

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <bcm2835.h>
#include "oled.h"

#define LCD_DC  20     // 模式选择 1:写数据 0:写命令
#define LCD_DIN 10     // 串行数据线
#define LCD_CLK 11     // 串行时钟线
#define LCD_RST 21     // 复位信号  低电平有效
#define LCD_CE  8     // 芯片使能  低电平有效

void oled_write_one_byte(uint8_t dat,uint8_t mode)
{ 
    if (mode == OLED_DATA) { // 写数据
        bcm2835_gpio_write(LCD_DC,HIGH);
    }
    else { // 写命令
        bcm2835_gpio_write(LCD_DC,LOW);
    }
    bcm2835_spi_transfer(dat);
}

void set_rst_level(uint8_t level)
{
    if(level == 1)
    {
        bcm2835_gpio_write(LCD_RST,HIGH);
    }else
    {
        bcm2835_gpio_write(LCD_RST,LOW);
    }
}

void delay_ms(uint8_t ms)
{
    bcm2835_delay(ms);
}

int main(int argc, char **argv)
{
	if (!bcm2835_init())//所有外围io引脚初始化,之前已经分析过了
    {
        printf("bcm2835_init failed. Are you running as root??\n");
        return 1;
    }

    bcm2835_gpio_fsel(LCD_DC, BCM2835_GPIO_FSEL_OUTP); //设置为输出模式
    bcm2835_gpio_fsel(LCD_RST,BCM2835_GPIO_FSEL_OUTP); //设置为输出模式

    if (!bcm2835_spi_begin())    {
        printf("bcm2835_spi_begin failed. Are you running as root??\n");
        return 1;
    }

    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);  
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); 
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_32);  
    bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
    bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); 

    OLED_Init();
    OLED_Clear();
    OLED_ShowString(0,0,(char*)"HELLO3 world",16,1);
    OLED_Refresh();//更新显示
    
     
    bcm2835_spi_end();  
    bcm2835_close();
 
    return 0;
}

然后编译这段代码

gcc -Wall main.c oled.c -o main -lbcm2835

-Wall 表示编译时显示所有警告,-lbcm2835 表示编译时动态加载bcm2835 库

编译完成后调用生成的main文件

sudo ./main

想要停止这个程序,Ctrl+c即可。

RPi.GPIO

python控制iic的话,是有专门的别人写好的库。有两个库可以选择luma和Adafruit,但是我们下面的使用只使用luma。

pip install luma.oled

我们使用python安装的时候,应该会报错error: externally-managed-environment,网上有几种方法解决,可以参考这篇博文,我使用的是他说的创建venv的方式。

python -m venv ~/myenv        #创建虚拟环境,myenv就是环境名
source ~/myenv/bin/activate   #使能我们创建的虚拟环境
pip install luma.oled         #再次Pip安装

其他env操作

deactivate #退出环境

直接给代码了,python应该比较好理解

from luma.core.interface.serial import i2c, spi
from luma.core.render import canvas
from luma.oled.device import ssd1306

# 创建 SPI 设备,使用 SPI-0
serial = spi(device=0, port=0, gpio_RST=21, gpio_DC=20)

# 创建屏幕的驱动实例
device = ssd1306(serial)

# 开始往屏幕上绘图。draw 是 Pillow 的实例,它里面还有非常多的绘图 API。
with canvas(device) as draw:
  draw.rectangle(device.bounding_box, outline="white", fill="black")
  draw.text((30, 40), "Hello World!", fill="white")

# 这行是为了阻止程序退出,因为退出的时候会调用析构函数,清空屏幕。防止一闪而过,什么也看不到。
while (True):
  pass

更多资料可查看https://github.com/rm-hull/luma.examples

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2055047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言 ——— 学习并使用malloc和free函数

目录 malloc函数的功能 学习malloc函数​编辑 使用malloc函数 free函数的功能 学习并使用free函数​编辑 malloc动态开辟10个整型空间后赋值为0-9&#xff0c;再打印&#xff0c;打印后free malloc函数的功能 malloc函数能向内存申请一块连续可用的空间&#xff0c;并返…

模拟信号-放大器

放大器 放大器的输出信号是直流源和信号源经过放大器后&#xff0c;共同的作用&#xff0c;缺一不可。 直流参数 与放大器中电压源部分有关的参数&#xff0c;即放大器的直流参数。 采用直流电压源供电&#xff0c;电源电压是恒定的&#xff0c;但是电压源的输出电流是变化…

什么是OV SSL证书?如何申请

什么是OVSSL证书 OVSSL证书&#xff0c;全称是Organization Validation SSL Certificate&#xff0c;即组织验证型SSL证书。这是一种高级的SSL证书类型&#xff0c;用于保护网站和应用程序的安全性&#xff0c;特别是在电子商务和企业级网站中广泛应用。OVSSL证书不仅加密网站…

Linux:进程替换

什么是进程替换&#xff1f; 我们的可执行程序&#xff0c;在运行起来的时候就上一个进程 一个进程就会有他的内核数据结构代码和数据 把一个已经成型的进程的代码和数据替换掉&#xff0c;这就叫进程替换 也就是可以通过系统调用把当前进程替换位我们需要的进程 那么替换…

正点原子linux开发板 qt程序交叉编译执行

1.开发板光盘 A-基础资料->5、开发工具->1、交叉编译器->fsl-imx-x11-glibc-x86_64-meta-toolchain-qt5-cortexa7hf-neon-toolchain-4.1.15-2.1.0.sh 拷贝到 Ubuntu 虚拟机 用文件传输系统或者共享文件夹传输到linux虚拟机 用ls -l查看权限&#xff0c;如果是白色的使…

【银河麒麟高级服务器操作系统】实际案例分析,xfsaild占用过高

了解银河麒麟操作系统更多全新产品&#xff0c;请点击访问麒麟软件产品专区&#xff1a;https://product.kylinos.cn 服务器环境及配置 物理机/虚拟机 物理机 处理器&#xff1a; Intel(R) Xeon(R) Silver 4110 CPU 2.10GHz 内存&#xff1a; 65536 MiB (64 GiB) 主板…

HTML5简洁的通用网站模板源码

文章目录 1.设计来源1.1 主界面1.2 模板页面11.3 模板页面21.4 模板页面31.5 模板页面41.6 模板页面5 2.效果和源码2.1 动态效果2.2 源码目录2.3 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/1413235…

【AD24报错】GND contains IO Pin and Power Pin objects 的解决方案

【AD24报错】GND contains IO Pin and Power Pin objects 的解决方案 在原理图设计过程中&#xff0c;在元器件接线引脚位置出现红色波浪线&#xff0c;显示错误GND contains IO Pin and Power Pin objects。 点击错误信息可以直接跳转到相关位置。 经查明&#xff0c;是在元…

【FPGA数字信号处理】- 数字信号处理如何入门?

​数字信号处理&#xff08;Digital Signal Processing&#xff0c;简称DSP&#xff09;是一种利用计算机或专用数字硬件对信号进行处理的技术&#xff0c;在通信、音频、视频、雷达等领域发挥着越来越重要的作用&#xff0c;也是FPGA主要应用领域之一。 本文将详细介绍数字信…

高德地图数据采集器|高德地图数据采集软件_一键导出表格

南斗地图数据采集是一款专业采集百度地图、360地图、高德地图、腾讯地图、必应、google、公司、店铺的手机、座机、地址、坐标等数据信息的软件&#xff0c;它与同类软件相比最显著特点是采集地图更专业、采集速度更快、采集更精准、操作方法更简单。 可以导出地图搜索结果数据…

运维学习————Linux环境下Tomcat的部署

目录 一、环境准备 二、 启动测试 三、访问端口修改 四、部署web项目 1、材料准备 2、部署 2.1、上传war包到webapps目录下 2.2、修改项目配置 2.3、浏览器访问 引申 一、环境准备 tomcat安装包&#xff1a;apache-tomcat-9.0.52 JDK环境&#xff1a; 我使用的y…

【TCP】连接管理:三次握手和四次挥手

连接管理 建立连接&#xff1a;三次握手断开连接&#xff1a;四次挥手 网络中的握手/挥手&#xff0c;就是发送不携带业务数据&#xff08;没有载荷&#xff0c;只有报头&#xff09;的数据包&#xff0c;但是能起到“打招呼”这样的效果。次数就是指网络通信的次数。 建立连…

【数学分析笔记】第2章第2节数列极限(3)

2. 数列极限 2.2 数列极限 2.2.5 数列极限的性质 保序性&#xff1a;【定理2.2.3】 { x n } , { y n } , lim ⁡ n → ∞ x n a , lim ⁡ n → ∞ y n b , a < b \{x_{n}\},\{y_{n}\},\lim\limits_{n\to\infty}x_{n}a,\lim\limits_{n\to\infty}y_{n}b,a<b {xn​},{yn…

Android强大的滚动控件RecyclerView

文章目录 Android强大的滚动控件RecyclerViewRecyclerView的基本用法RecyclerView实现横向滚动RecyclerView实现瀑布流布局RecyclerView**的点击事件 Android强大的滚动控件RecyclerView ListView由于其强大的功能&#xff0c;在过去的Android开发当中可以说是贡献卓越&#x…

C语言 | Leetcode C语言题解之第350题两个数组的交集II

题目&#xff1a; 题解&#xff1a; int cmp(const void* _a, const void* _b) {int *a _a, *b (int*)_b;return *a *b ? 0 : *a > *b ? 1 : -1; }int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size,int* returnSize) {qsort(nums1, nums1Size, s…

你还在手动刷公众号吗?‌试试 RSS 订阅,‌让信息自动汇聚

微信对于反爬的限制非常严格&#xff0c;之前有很多的方案&#xff0c;最后都是被封杀了。我这里列出一些我知道的、实践过的方案。 ‍ RSSHub 在路由“社交媒体”以及路由“新媒体”上都有很多方案&#xff0c;我基本都试过&#xff0c;但这些平台要么是收费的&#xff0c;…

图像数据处理17

四、形态学图像处理 4.3 开运算与闭运算 4.3.1开运算与闭运算的定义&#xff1a; 开运算&#xff1a;先腐蚀&#xff0c;再膨胀 闭运算&#xff1a;先膨胀&#xff0c;再腐蚀 记忆方法&#xff1a;膨胀&#xff08;胀开&#xff09;所以开运算最后对应的结果是膨胀&#x…

学习GitHub:注册与Linux环境对工作内容进行库分支上传

在这个数字化时代&#xff0c;GitHub已成为开发者们不可或缺的宝藏库。无论你是编程新手还是资深开发者&#xff0c;GitHub都能为你打开一扇通往无限创意与协作的大门。今天&#xff0c;就让我们一起踏上这段探索之旅&#xff0c;从GitHub的注册开始&#xff0c;再到如何在Linu…

blender内置树木的UV

之前听说用这个内置插件可以创建树木 我这边的默认配置出来的树木长这样&#xff0c;不得不想一下&#xff0c;他的uv怎么展&#xff0c;看起来好多树 我尝试看了一眼默认的UV 结果如下 好像每个树枝都已经是平铺的样子了&#xff0c;那么如果需要改的话&#xff0c;就根据…

SpringBoot 整合 Excel 轻松实现数据自由导入导出

01、背景介绍 在实际的业务系统开发过程中&#xff0c;操作 Excel 实现数据的导入导出基本上是个非常常见的需求。 之前&#xff0c;我们有介绍一款非常好用的工具&#xff1a;EasyPoi&#xff0c;有读者提出在数据量大的情况下&#xff0c;EasyPoi 会占用内存大&#xff0c;…