• GPIO 模拟SPI


    SPI简介

    SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。
    SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。

    • SDO(MOSI): 主设备数据输出,从设备数据输入
    • SDI(MISO):主设备数据输入,从设备数据输出
    • SCLK : 时钟信号,由主设备产生
    • CS :从设备使能信号,由主设备控制

    SCPH=0,SCPOL=0 的 SPI 协议时序图在这里插入图片描述

    SCPH=1,SCPOL=0 的 SPI 协议时序图

    在这里插入图片描述

    SCPH=0,SCPOL=1 的 SPI 协议时序图

    在这里插入图片描述

    SCPH=1,SCPOL=1 的 SPI 协议时序图

    在这里插入图片描述

    GPIO模拟

    定义出MISO、MOSI、CS、CLK等

    #define CS_GPIO                       (0)
    #define CLK_GPIO                      (1)
    #define MOSI_GPIO                     (2)
    #define MISO_GPIO                     (3)
    #define IRQ_GPIO                      (4)
    
    #define CS(a)                         Set_SPI_Related_Gpio(a, CS_GPIO)
    #define DCLK(a)                       Set_SPI_Related_Gpio(a, CLK_GPIO)
    #define DIN(a)                        Set_SPI_Related_Gpio(a, MOSI_GPIO)
    #define DOUT()                        Get_SPI_Related_Gpio(MISO_GPIO)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    往从设备发送数据

    /**
      * @brief  Write Byte to LCD
      * @param  byte : Byte
      */
    void WriteByteSPI(unsigned char byte)
    {
        unsigned char buf;
        unsigned char i;
        CS(0);
        for(i=0;i<8;i++) 
        {
            buf=(byte>>(7-i))&0x1;
            DIN(buf);
            DCLK(0);
            DCLK(1);
        }	
        CS(1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    从设备读取数据

    /**
      * @brief  Read data from spi
      */
    static unsigned short ReadByteSPI(void) 
    {
        unsigned short buf=0,temp;
        unsigned char i;
        uint level = 0;
        DIN(0);
        DCLK(1);
        CS(0);
        for(i=0;i<8;i++)
        {
            DCLK(0);
            level = DOUT();
            temp= (level) ? 1:0;
            buf|=(temp<<(7-i));
            //Delayus(5);
            DCLK(0);
            DCLK(1);
        }
        CS(1);
        buf&=0xff;
        return(buf);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    stm32上完整demo

    //LCD.h
    #include "HAL_conf.h"
    
    #define SPI_CS(a)	\
    						if (a)	\
    						GPIOA->BSRR = GPIO_Pin_4;	\
    						else		\
    						GPIOA->BRR = GPIO_Pin_4;
    #define SPI_DCLK(a)	\
    						if (a)	\
    						GPIOA->BSRR = GPIO_Pin_5;	\
    						else		\
    						GPIOA->BRR = GPIO_Pin_5;
    #define SPI_SDA(a)	\
    						if (a)	\
    						GPIOA->BSRR = GPIO_Pin_7;	\
    						else		\
    						GPIOA->BRR = GPIO_Pin_7;
    #define lcd_RS(a)	\
    						if (a)	\
    						GPIOA->BSRR = GPIO_Pin_3;	\
    						else		\
    						GPIOA->BRR = GPIO_Pin_3;
    
    #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 //灰色
    
    void LCD_Initial(void); //LCD初始化函数
    void Delayms(unsigned short time);
    void LCD_WriteRegIndex(unsigned char Index);
    void LCD_WriteData(unsigned short dat);
    void LCD_WR_REG(u16 Index,u16 CongfigTemp);
    void Lcd_SetCursor(u16 x,u16 y);
    void SPILCD_SetWindow(unsigned short xstat,unsigned short xend,unsigned short ystat,unsigned short yend);
    void SPILCD_DrawPoint(unsigned short x,unsigned short y,unsigned short color);
    void SPILCD_Clear(unsigned short Color);
    void SPILCD_Clear_Fast(unsigned char single_Color);
    void SPILCD_Fill(unsigned short xsta,unsigned short ysta,unsigned short xend,unsigned short yend,unsigned short color);
    void SPILCD_DrawLine(unsigned short x1,unsigned short y1,unsigned short x2,unsigned short y2,unsigned short color);
    void SPILCD_ShowChar(unsigned short x,unsigned short y,unsigned char num, unsigned int fColor, unsigned int bColor,unsigned char flag) ;
    void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag);
    void LCD_Fill_Pic(u16 x, u16 y,u16 pic_H, u16 pic_V, const unsigned char* pic);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    //LCD.c
    #include "LCD.h"
    #include "ASCII.h"
    #include "GB1616.h"	//16*16汉字字模
    #define SPILCD_W 176
    #define SPILCD_H 220
    
    void Delayms(unsigned short time)  //延时函数
    {
    	unsigned short i,j;
    	for(i=0;i<time;i++)
    		for(j=0;j<5000;j++)	;
    }
    
    void LCD_WriteByteSPI(unsigned char byte) //SPI模拟函数,写一个8bit的数据
    {
    	  unsigned char buf;
        unsigned char i;
        for(i=0;i<8;i++) 
        {
            buf=(byte>>(7-i))&0x1;
            SPI_SDA(buf);
    				SPI_DCLK(0);
            SPI_DCLK(1);
        }	
    }
    void LCD_WriteoneSPI(unsigned char byte) //写一个4bit的数据
    {
    	  unsigned char buf;
        unsigned char i;
    	
        for(i=0;i<4;i++) 
        {
            buf=(byte>>(3-i))&0x1;
            SPI_SDA(buf);
    				SPI_DCLK(0);
            SPI_DCLK(1);
        }	
    
    }
    void WriteComm(unsigned char dat) //写命令
    {
    //	SPI_CS(0);
    	lcd_RS(0);
    	LCD_WriteByteSPI(dat);	
    	lcd_RS(1);
    //	SPI_CS(1);
    }
    void LCD_WriteRegIndex(unsigned char Index) //写命令的参数
    {
    	lcd_RS(0);
    	LCD_WriteByteSPI(Index);
    	lcd_RS(1);
    }
    void LCD_WriteData(unsigned short dat) //写数据
    {
      LCD_WriteByteSPI(dat>>8);		//	start byte RS=1,RW=0----Write a GRAM data
      LCD_WriteByteSPI(dat);
    }
    /******************************************
    函数名:Lcd写命令函数
    功能:向Lcd指定位置写入应有命令或数据
    入口参数:Index 要寻址的寄存器地址
              ConfigTemp 写入的数据或命令值
    ******************************************/
    void LCD_WR_REG(u16 Index,u16 CongfigTemp)
    {
    	LCD_WriteRegIndex(Index);
    	LCD_WriteByteSPI(CongfigTemp);
    //LCD_WriteData(CongfigTemp);
    }
    
    void LCD_Initial(void) //LCD初始化函数
    {
    
    	GPIO_SetBits(GPIOA, GPIO_Pin_2);//打开背光
    
    		//Power Voltage Setting 
    LCD_WR_REG(0x1A,0x02);     //BT 
    LCD_WR_REG(0x1B,0x88);     //VRH 
     
    //****VCOM offset**/// 
    LCD_WR_REG(0x23,0x00);     //SEL_VCM 
    LCD_WR_REG(0x24,0xEE);     //VCM 
    LCD_WR_REG(0x25,0x15);     //VDV 
     
    LCD_WR_REG(0x2D,0x03);     //NOW[2:0]=011 
     
    //Power on Setting 
    LCD_WR_REG(0x18,0x1E);     //Frame rate 72Hz 
    LCD_WR_REG(0x19,0x01);     //OSC_EN='1', start Osc 
    LCD_WR_REG(0x01,0x00);     //DP_STB='0', out deep sleep 
    LCD_WR_REG(0x1F,0x88);    //STB=0 
    Delayms(5); 
    LCD_WR_REG(0x1F,0x80);      //DK=0 
    Delayms(5); 
    LCD_WR_REG(0x1F,0x90);    //PON=1 
    Delayms(5); 
    LCD_WR_REG(0x1F,0xD0);    //VCOMG=1 
    Delayms(5); 
     LCD_WR_REG(0x2F,0x00);
    //262k/65k color selection 
    LCD_WR_REG(0x17,0x05);     //default 0x06 262k color // 0x05 65k color 
     
    //SET PANEL 
    LCD_WR_REG(0x16,0xA0);
    LCD_WR_REG(0x36,0x09);     //REV_P, SM_P, GS_P, BGR_P, SS_P 
    LCD_WR_REG(0x29,0x31);     //400 lines 
    LCD_WR_REG(0x71,0x1A);     //RTN 
    
    //Gamma 2.2 Setting     
     LCD_WR_REG(0x40,0x01); 
     LCD_WR_REG(0x41,0x08); 
     LCD_WR_REG(0x42,0x04); 
     LCD_WR_REG(0x43,0x2D); 
     LCD_WR_REG(0x44,0x30); 
     LCD_WR_REG(0x45,0x3E); 
     LCD_WR_REG(0x46,0x02); 
     LCD_WR_REG(0x47,0x69); 
     LCD_WR_REG(0x48,0x07); 
     LCD_WR_REG(0x49,0x0E); 
     LCD_WR_REG(0x4A,0x12); 
     LCD_WR_REG(0x4B,0x14); 
     LCD_WR_REG(0x4C,0x17); 
     
     LCD_WR_REG(0x50,0x01); 
     LCD_WR_REG(0x51,0x0F); 
     LCD_WR_REG(0x52,0x12); 
     LCD_WR_REG(0x53,0x3B); 
     LCD_WR_REG(0x54,0x37); 
     LCD_WR_REG(0x55,0x3E); 
     LCD_WR_REG(0x56,0x16); 
     LCD_WR_REG(0x57,0x7D); 
     LCD_WR_REG(0x58,0x08); 
     LCD_WR_REG(0x59,0x0B); 
     LCD_WR_REG(0x5A,0x0D); 
     LCD_WR_REG(0x5B,0x11); 
     LCD_WR_REG(0x5C,0x18); 
     LCD_WR_REG(0x5D,0xFF); 
     
    LCD_WR_REG(0x1B,0x001a); //VRH 
    LCD_WR_REG(0x25,0x0055); //NVRH 
    LCD_WR_REG(0x1A,0x0010); //BT 
    LCD_WR_REG(0x1E,0x0038); //FS1   
    
    //Display ON Setting 
    LCD_WR_REG(0x28,0x38);      //GON=1, DTE=1, D=10 
    Delayms(40); 
    LCD_WR_REG(0x28,0x3C);      //GON=1, DTE=1, D=11 
     
    WriteComm(0x22);               //Start GRAM write 
    }
    
    
    
    
    /*************************************************
    函数名:Lcd光标起点定位函数
    功能:指定320240液晶上的一点作为写数据的起始点
    入口参数:x 坐标 0~239
              y 坐标 0~319
    返回值:无
    *************************************************/
    void Lcd_SetCursor(u16 x,u16 y)
    { 
      LCD_WriteRegIndex(0x20);
      LCD_WriteData(x);//水平坐标
      LCD_WriteRegIndex(0x21);
      LCD_WriteData(y);//垂直坐标 
    } 
    void SPILCD_SetWindow(unsigned short xstat,unsigned short xend,unsigned short ystat,unsigned short yend)
    {
    	//Set GRAM Area 
    	LCD_WR_REG(0x02,xstat>>8); 
    	LCD_WR_REG(0x03,xstat&0xff);     //Column Start 
    	LCD_WR_REG(0x04,xend>>8); 
    	LCD_WR_REG(0x05,xend&0xff);     //Column End 
    	 
    	LCD_WR_REG(0x06,ystat>>8); 
    	LCD_WR_REG(0x07,ystat&0xff);     //Row Start 
    	LCD_WR_REG(0x08,yend>>8); 
    	LCD_WR_REG(0x09,yend&0xff);     //Row End 
    
    	WriteComm(0x22);
    }
    void SPILCD_Fill(unsigned short xsta,unsigned short ysta,unsigned short xend,unsigned short yend,unsigned short color)
    {                    
    	unsigned short i,j;
    	//设置窗口		
    	SPILCD_SetWindow(xsta,xend-1,ysta,yend-1);
    	for(i=xsta;i<=xend;i++)
    		for(j=ysta;j<=yend;j++)
    	{
    		   	LCD_WriteData(color);	  //显示所填充的颜色. 
    	}    
    }
    /******************************************
    函数名:Lcd图像填充100*100
    功能:向Lcd指定位置填充图像
    入口参数:
    ******************************************/
    void LCD_Fill_Pic(u16 x, u16 y,u16 pic_H, u16 pic_V, const unsigned char* pic)
    {
      unsigned long i,j;
    	j=pic_H*pic_V*2;
    	SPILCD_SetWindow(x,x+pic_H-1,y,y+pic_V-1);
    	for (i = 0; i < j; i++)
    	{
        LCD_WriteByteSPI(pic[i]);
    	}
    }
    //=============== 在x,y 坐标上打一个颜色为Color的点 ===============
    void DrawPixel(u16 x, u16 y, int Color)
    {
    	SPILCD_SetWindow(x,x,y,y); 
      LCD_WriteData(Color);							  
    }
    //------------------------------------------------------------------------------------------------------------
    //------------------------------------------------------------------------------------------------------------
    //8*16字体 ASCII码 显示
    //函数名:SPILCD_ShowChar
    //参  数:
    //(x,y): 
    //num:要显示的字符:" "--->"~"
    //flag:有背景色(1)无背景色(0)
    void SPILCD_ShowChar(unsigned short x,unsigned short y,unsigned char num, unsigned int fColor, unsigned int bColor,unsigned char flag) 
    {       
    	unsigned char temp;
    	unsigned int pos,i,j;  
    
    	num=num-' ';//得到偏移后的值
    	i=num*16; 	
    	for(pos=0;pos<16;pos++)
    		{
    			temp=nAsciiDot[i+pos];	//调通调用ASCII字体
    			for(j=0;j<8;j++)
    		   {                 
    		        if(temp&0x80)
    							DrawPixel(x+j,y,fColor);
    						else 
    							if(flag) DrawPixel(x+j,y,bColor); //如果背景色标志flag为1
    							temp<<=1; 
    		    }
    			 y++;
    		}		 
    }  
    
    //写一个16x16的汉字
    void PutGB1616(unsigned short x, unsigned short  y, unsigned char c[2], unsigned int fColor,unsigned int bColor,unsigned char flag)
    {
    	unsigned int i,j,k;
    	unsigned short m;
    	for (k=0;k<64;k++) { //64标示自建汉字库中的个数,循环查询内码
    	  if ((codeGB_16[k].Index[0]==c[0])&&(codeGB_16[k].Index[1]==c[1]))
    			{ 
        	for(i=0;i<32;i++) 
    			{
    				m=codeGB_16[k].Msk[i];
    				for(j=0;j<8;j++) 
    				{		
    					if((m&0x80)==0x80) {
    						DrawPixel(x+j,y,fColor);
    						}
    					else {
    						if(flag) DrawPixel(x+j,y,bColor);
    						}
    					m=m<<1;
    				} 
    				if(i%2){y++;x=x-8;}
    				else x=x+8;
    		  }
    		}  
    	  }	
    	}
    
    //显示一串字
    void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag) 
    {
    	unsigned char l=0;
    	while(*s) 
    		{
    			if( *s < (char)0x80) 
    					{
    						SPILCD_ShowChar(x+l*8,y,*s,fColor,bColor,flag);
    						s++;l++;
    					}
    			else
    					{
    						PutGB1616(x+l*8,y,(unsigned char*)s,fColor,bColor,flag);
    						s+=2;l+=2;
    					}
    		}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
  • 相关阅读:
    推荐计划常见问题解答:有哪些问题是必须的?
    百数服务商——顶杰云,为建筑行业数字化转型“添砖加瓦”
    # Unity 如何获取Texture 的内存大小
    React和vue等前端html页面引入自定义字体文件,更改页面字体样式
    38.sed高级编辑命令
    学生动漫网页设计模板下载你的名字 大学生HTML网页制作作品 简单漫画网页设计成品 dreamweaver学生网站模板
    查看docker容器IP地址
    E. Mishap in Club
    14.haproxy+keepalived负载均衡和高可用
    FlinkModule加载HiveModule异常
  • 原文地址:https://blog.csdn.net/qq_29890089/article/details/127449560