栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

树莓派4B学习笔记——IO通信篇(SPI)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

树莓派4B学习笔记——IO通信篇(SPI)

文章目录

SPI协议简介树莓派4B+1.3寸OLED(SPI协议)

1.3寸OLED简介接线图开启树莓派SPI接口wiringPiSPI库简介C语言实现(汉字、字符、数字、图片显示)Python实现 总结

SPI协议简介

SPI(Serial Peripheral interface):是由Motorola公司开发的串行外围设备接口,是一种高速的,全双工,同步的通信总线。主要应用在FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器等器件。
它是串行、全双工、 同步(使用时钟)、板级通信,一般是高位先发(也可以设置为低位先发)。
标准四线SPI引脚定义如下:

引脚定义功能
SCLK时钟线,用于主从时序的同步
CS片选信号线,用于选择跟哪个芯片进行通信
MOSI数据线,主出从入
MISO数据线,master input slave output 主入从出

有时也会根据通信需求设计时只采取三线模式,毕竟不是所有的系统都需要主从之间实现全双工的通信,大多是只需要主机发送数据控制从机即可,所以硬件设计时会采用舍去MISO。我们今天使用的1.3寸OLED就是使用的3线模式(关于SPI这个三线四线的定义emmm有好几个说法,还有种说法是根据有没有单独的片选线而定,这里不纠结,毕竟也没有官方的定义。)。
一主一从接线方式:

一个主机对多个从机,总线挂载多个SPI从机,这里的挂在数量是根据你的片选信号个数而定的。

SPI的传输速度会比前面使用的I2C快,其传输速度可达几Mb/s,设置SPI的通信速度时,一定不能大于从机的最大通信速度 。如果大于从机的通信速度,会导致通信失败。
SPI的通讯流程:
主机:我要给从机1传命令(主发送从接收),先把从机1给叫到办公室(CS片选选中从机1),然后开始传送命令,传输完毕后从机1离开办公室(CS恢复),主机可以重新选择传输对象。
有关SPI的四种模式等详细介绍,参考此文。

树莓派4B+1.3寸OLED(SPI协议) 1.3寸OLED简介

使用的是中景原子的1.3寸OLED,这种屏幕的好处在于它兼容I2C和SPI,自己改一下元器件的焊接位置即可,以下来自厂家描述:
7针和6针两种屏均支持SPI/IIC,默认为SPI接口出货。将电阻SPI拆掉焊接到到IIC位置;R4两端用锡短接,DC,CS管脚接地;RES管脚通过一个IO去控制完成复位;复位方法先将RES管脚保持低电平200ms;然后将RES管脚操持高平完成复位操作,然后对OLED进行初始化操作;这样就可以用iic通信了; 时钟=SCL; 数据线=SDA。
这里特别说明一下DC管脚,在用IIC通信的时候DC管脚的高低电平是用来设置IIC设备地址的;一般常用是将DC直接接地了,如果IIC总线上有两个OLED屏,就需要一个将DC接地,另一个DC接高电平;这样两个OLED屏的IIC地址就会不同了,可以分时操作两个屏6针与7针的不同是将CS管脚直接接地了;这样用户可以节省一个IO,不过这样的话6针的屏在用SPI接口的时候,就不能与其它SPI复用了,7脚的可以。

接线图

在终端命令行输入 gpio readall 回车可以找到树莓派的板载硬件SPI接口。

我们对照上面的引脚和实物接线就可以了,这里我也是参考的是此博文,如果是用的0.96寸屏幕直接参考链接里面接线即可。

开启树莓派SPI接口

打开终端命令,输入ls /dev 回车

发现没有SPI节点,这是因为系统默认是关闭了SPI接口的,需要我们自己打开。
跟昨天I2C的步骤一样,终端界面就是输入sudo raspi-config,参考上一篇将SPI enable即可,不清楚的可以去看上一篇,这里不再一步一步贴图了,开启后还是重启一下树莓派。

打开终端命令输入 ls /dev回车

可以看见有spidev0.0和spidev0.1两个节点说明SPI已经开启。

wiringPiSPI库简介

打开wiringPiSPI.h,我们可以看见里面外部声明了四个函数,也就是说,我们通过这四个函数即可实现spi的使用。

有关这四个函数的详细介绍参考此文。

C语言实现(汉字、字符、数字、图片显示)

打开Geany输入以下代码(移植的中景园电子的源代码)

// An highlighted block
#include 
#include   
#include 

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

#define OLED_MODE 0
#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 u16 unsigned int 
#define u8  unsigned char
const unsigned char F6x8[][6];
const unsigned char F8X16[];
unsigned char BMP2[];
unsigned char BMP1[];
unsigned char picture6[];
unsigned char picture7[];
unsigned char picture8[];
unsigned char picture9[];
char Hzk[][32];
#define X_Col_addr  0x80  // 定位列 地址 0-83
#define Y_Row_addr  0x40  // 定位行 地址 0-5				
// 初始化GPIO 端口
void gpioInit(){
    pinMode(LCD_DC,OUTPUT);
    pinMode(LCD_RST,OUTPUT);
    pinMode(LCD_CE,OUTPUT);
}

void OLED_Set_Pos(unsigned char x, unsigned char y) 
{ 
	lcd_writeByte(0xb0+y,OLED_CMD);
	lcd_writeByte((((x+2)&0xf0)>>4)|0x10,OLED_CMD);
	lcd_writeByte(((x+2)&0x0f),OLED_CMD); 
} 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void lcd_clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		lcd_writeByte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		lcd_writeByte (0x02,OLED_CMD);      //设置显示位置—列低地址
		lcd_writeByte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)lcd_writeByte(0,OLED_DATA); 
	} //更新显示
}

//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{      			    
	u8 t,adder=0;
	OLED_Set_Pos(x,y);	
    for(t=0;t<16;t++)
		{
				lcd_writeByte(Hzk[2*no][t],OLED_DATA);
				adder+=1;
     }	
		OLED_Set_Pos(x,y+1);	
    for(t=0;t<16;t++)
			{	
				lcd_writeByte(Hzk[2*no+1][t],OLED_DATA);
				adder+=1;
      }					
}


void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{ 	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0) y=y1/8;      
  else y=y1/8+1;
	for(y=y0;yMax_Column-1){x=0;y=y+2;}
		if(SIZE ==16)
			{
			OLED_Set_Pos(x,y);	
			for(i=0;i<8;i++)
			lcd_writeByte(F8X16[c*16+i],OLED_DATA);
			OLED_Set_Pos(x,y+1);
			for(i=0;i<8;i++)
			lcd_writeByte(F8X16[c*16+i+8],OLED_DATA);
			}
			else {	
				OLED_Set_Pos(x,y+1);
				for(i=0;i<6;i++)
				lcd_writeByte(F6x8[c][i],OLED_DATA);
				
			}
}

//m^n函数
unsigned int oled_pow(u8 m,u8 n)
{
	unsigned int result=1;	 
	while(n--)result*=m;    
	return result;
}				  
//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,unsigned int num,u8 len,u8 size)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t120){x=0;y+=2;}
			j++;
	}
}



// 初始化液晶
void lcd_init(){
    gpioInit();
    int isOK = wiringPiSPISetup(0, 1000000);
    if (isOK == -1) {
        printf("SPI设置失败n");
    }
    else {
        printf("SPI设置OK == %dn",isOK);
    }
    digitalWrite(LCD_RST,LOW); // 液晶复位
    delay(200);
    digitalWrite(LCD_RST,HIGH);
    delay(20);
    	lcd_writeByte(0xAE,OLED_CMD);//--turn off oled panel
	lcd_writeByte(0x02,OLED_CMD);//---set low column address
	lcd_writeByte(0x10,OLED_CMD);//---set high column address
	lcd_writeByte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	lcd_writeByte(0x81,OLED_CMD);//--set contrast control register
	lcd_writeByte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
	lcd_writeByte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
	lcd_writeByte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
	lcd_writeByte(0xA6,OLED_CMD);//--set normal display
	lcd_writeByte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	lcd_writeByte(0x3f,OLED_CMD);//--1/64 duty
	lcd_writeByte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	lcd_writeByte(0x00,OLED_CMD);//-not offset
	lcd_writeByte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
	lcd_writeByte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 frames/Sec
	lcd_writeByte(0xD9,OLED_CMD);//--set pre-charge period
	lcd_writeByte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	lcd_writeByte(0xDA,OLED_CMD);//--set com pins hardware configuration
	lcd_writeByte(0x12,OLED_CMD);
	lcd_writeByte(0xDB,OLED_CMD);//--set vcomh
	lcd_writeByte(0x40,OLED_CMD);//Set VCOM Deselect Level
	lcd_writeByte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
	lcd_writeByte(0x02,OLED_CMD);//
	lcd_writeByte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
	lcd_writeByte(0x14,OLED_CMD);//--set(0x10) disable
	lcd_writeByte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
	lcd_writeByte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) 
	lcd_writeByte(0xAF,OLED_CMD);//--turn on oled panel
	
	lcd_writeByte(0xAF,OLED_CMD);  
    lcd_clear(); // 清屏
    OLED_Set_Pos(0,0); 
}

int main (void)
{
	unsigned char t;
    wiringPiSetup();
    lcd_init();
    lcd_clear(); // 清屏
    t=' ';
    while(1)
    {
		lcd_clear();
	//	LED_ON;
		OLED_ShowCHinese(0,0,0);//中
		OLED_ShowCHinese(18,0,1);//景
		OLED_ShowCHinese(36,0,2);//园
		OLED_ShowCHinese(54,0,3);//电
		OLED_ShowCHinese(72,0,4);//子
		OLED_ShowCHinese(90,0,5);//科
		OLED_ShowCHinese(108,0,6);//技
		OLED_ShowString(0,3,"1.3' OLED TEST");
		//OLED_ShowString(8,2,"ZHONGJINGYUAN");  
	 //	OLED_ShowString(20,4,"2014/05/01");  
		OLED_ShowString(0,6,"ASCII:");  
		OLED_ShowString(63,6,"CODE:");  
		OLED_ShowChar(48,6,t);//显示ASCII字符	   
		t++;
		if(t>'~')t=' ';
		OLED_ShowNum(103,6,t,3,16);//显示ASCII字符的码值 	
		delay(2000);
		lcd_clear();
		delay(100);
	//		LED_OFF;
		OLED_DrawBMP(0,0,128,8,BMP1);  //图片显示(图片显示慎用,生成的字表较大,会占用较多空间,FLASH空间8K以下慎用)
		delay(1000);
		OLED_DrawBMP(0,0,128,8,picture6);  //图片显示(图片显示慎用,生成的字表较大,会占用较多空间,FLASH空间8K以下慎用)
		delay(200);
		OLED_DrawBMP(0,0,128,8,picture7);
		delay(200);
		OLED_DrawBMP(0,0,128,8,picture8);  //图片显示(图片显示慎用,生成的字表较大,会占用较多空间,FLASH空间8K以下慎用)
		delay(200);
		OLED_DrawBMP(0,0,128,8,picture9);
		delay(200);
		OLED_DrawBMP(0,0,128,8,picture6);  //图片显示(图片显示慎用,生成的字表较大,会占用较多空间,FLASH空间8K以下慎用)
		delay(200);
		OLED_DrawBMP(0,0,128,8,BMP2);
		delay(1000);
	}
}
//取模部分代码太长了,需要的去资源下载或者点赞收藏私信博主获取。

然后保存,编译,效果如下:

Python实现

此处参考此博文即可,Python部分主要是调用API接口,比C语言的取模要方便的多。
最终效果如下所示:

总结

有关SPI部分的使用就到这,欢迎大家提出指正。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/737802.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号