【SPI experiment--digital tube】

1. SPI concept

1. The SPI bus is a full-duplex three-wire/four-wire synchronous serial bus first proposed by Motorola
2. It adopts the master-slave mode (Master
Slave) architecture and supports multi-slave mode applications. In actual development and use, most of them use a single Master multi-slave mode
3. The clock is controlled by the Master. Under the clock shift pulse
, the data is transmitted bit by bit, with the high bit first and the low bit behind (MSB first), or the low bit first and the high bit behind
. There are two unidirectional data lines, which are full-duplex
communication. The data rate in current applications can reach the level of several Mbps
. Higher occasions
6. This experiment: SOC<—SPI bus—>digital tube

2. SPI hardware connection

SPI has a total of four signal lines: device selection line, clock line, serial output data line,
serial input data line
Device selection line (chip selection line): NSS
clock line: SCK
serial output data line: MOSI
serial input Data line: MISO
M: master host O: output output S: slave slave I: input input

• (1) MOSI: master device data output, slave device data input
• (2) MISO: master device data input, slave device data output
• (3) SCLK: clock signal, generated by the master device
• (4) /SS: Slave enable signal, controlled by master (chip select)

3. SPI bus communication protocol

insert image description here
Start signal: NSS signal line changes from high to low, which is the start signal of SPI communication End
signal: NSS signal changes from low to high, which is the stop signal of SPI communication
Data transmission: SPI uses MOSI and MISO signal lines to transmit data, use The SCK signal line performs data synchronization.
The MOSI and MISO data lines transmit one bit of data in each clock cycle of SCK, and the data input and output are carried out simultaneously
. Each SPI data transfer can be 8-bit or 16-bit as a unit, and the number of units per transfer is not limited

Four, SPI four communication modes

insert image description here

Five, the code realizes the digital tube

spi.h

#ifndef __SPI_H__
#define __SPI_H__
 
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
// MOSI对应的引脚输出高低电平的信号
#define  MOSI_OUTPUT_H()	do{
      
      GPIOE->ODR |= (0x1 << 14);}while(0)
#define  MOSI_OUTPUT_L()    do{
      
      GPIOE->ODR &= (~(0x1 << 14));}while(0)
 
// 对应595芯片的锁存引脚输出高低电平
#define  NSS_OUTPUT_H()	    do{
      
      GPIOE->ODR |= (0x1 << 11);}while(0)
#define  NSS_OUTPUT_L()     do{
      
      GPIOE->ODR &= (~(0x1 << 11));}while(0)
	
// 时钟信号对应的引脚输出高低电平
#define  SCK_OUTPUT_H()     do{
      
      GPIOE->ODR |= (0x1 << 12);}while(0)
#define  SCK_OUTPUT_L()     do{
      
      GPIOE->ODR &= (~(0x1 << 12));}while(0)
 
/*
 * 函数功能: SPI初始化函数,推挽输出,高速,禁止上拉和下拉
 * 函数参数:无
 * 函数返回值:无
*/
void SPI_init(void);
/*
 * 函数功能:SPI发送数据的函数
 * 函数参数:dat : 要发送的数据
 * 函数返回值:无
 *
*/
void SPI_write(unsigned char dat);
 
 
#endif  // __SPI_H__

spi.c

#include "spi.h"
/* SPI4_NSS 	---->   PE11
 * SPI4_SCK     ---->   PE12
 * SPI4_MOSI    ---->   PE14
 * SPI4_MISO    ---->   PE13
 * */
 
/* 数码管的编码, 先发送低位,在发送高位
 * A B C D E F G DP
 * 1 1 1 1 1 1 0 0    0xFC   0
 * 0 1 1 0 0 0 0 0    0x60   1
 * 1 1 0 1 1 0 1 0    0xDA   2
 * 1 1 1 1 0 0 1 0    0xF2   3
 * 0 1 1 0 0 1 1 0    0x66   4
 * 1 0 1 1 0 1 1 0    0xB6   5 
 * 1 0 1 1 1 1 1 0    0xBE   6
 * 1 1 1 0 0 0 0 0    0xE0   7
 * 1 1 1 1 1 1 1 0    0xFE   8
 * 1 1 1 1 0 1 1 0    0xF6   9
 * */
void delay_us1(unsigned int us)
{
    
    
	int i,j;
	for(i = 0; i < us;i++)
		for (j = 0; j < 1;j++);
}
 
void SPI_init(void)
{
    
    
	RCC->MP_AHB4ENSETR |= (0x1 << 4);
	// MOSI    PE14 
	GPIOE->MODER &= (~(0x3 << 28));
	GPIOE->MODER |= (0x1 << 28);
	GPIOE->OTYPER &= (~(0x1 << 14));
	GPIOE->OSPEEDR &= (~(0x3 << 28));
//	GPIOE->OSPEEDR |= (0x2 << 28);
	GPIOE->PUPDR &= (~(0x3 << 28));
	// MISO    PE13
	GPIOE->MODER &= (~(0x3 << 26));
	GPIOE->OSPEEDR &= (~(0x3 << 26));
//	GPIOE->OSPEEDR |= (0x2 << 26);
	GPIOE->PUPDR &= (~(0x3 << 26));
	// SCK     PE12	
	GPIOE->MODER &= (~(0x3 << 24));
	GPIOE->MODER |= (0x1 << 24);
	GPIOE->OTYPER &= (~(0x1 << 12));
	GPIOE->OSPEEDR &= (~(0x3 << 24));
//	GPIOE->OSPEEDR |= (0x2 << 24);
	GPIOE->PUPDR &= (~(0x3 << 24));
	// NSS     PE11
	GPIOE->MODER &= (~(0x3 << 22));
	GPIOE->MODER |= (0x1 << 22);
	GPIOE->OTYPER &= (~(0x1 << 11));
	GPIOE->OSPEEDR &= (~(0x3 << 22));
//	GPIOE->OSPEEDR |= (0x2 << 22);
	GPIOE->PUPDR &= (~(0x3 << 22));
	NSS_OUTPUT_L();    // 595芯片的锁存引脚拉低
	SCK_OUTPUT_L();    // SPI的时钟线拉低
}
 
void SPI_write(unsigned char dat)
{
    
    
	unsigned char i;
	for(i = 0; i < 8; i++)
	{
    
    
 
		if(dat & 0x01)
		{
    
    
			MOSI_OUTPUT_H();  // MOSI线写高
		} else {
    
    
			MOSI_OUTPUT_L();  // MOSI线写低
		}
		dat >>= 1;
		// 时钟线从低电平到高电平的变化时,MOSI数据线上的数据
		// 被写到595芯片的移位寄存器中
		SCK_OUTPUT_L();   // SCK拉低
		delay_us1(10);
		SCK_OUTPUT_H();   // SCK拉高
		delay_us1(10);
	}
	//NSS_OUTPUT_L();
	//NSS_OUTPUT_H();
 
}
 
 
 

main.c

#include "gpio.h"
#include "spi.h"
 
extern void printf(const char *fmt, ...);
 
void delay_ms(int ms)
 
{
    
    
 
	int i,j;
 
	for(i = 0; i < ms;i++)
 
		for (j = 0; j < 1800; j++);
 
}
 
 
int num[10] = {
    
    0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6};
 
int main(void)
 
{
    
    
 
	unsigned char i;
 
	SPI_init();
 
	while(1)
 
	{
    
    
 
#if 0
 
		for(i = 0; i < 10; i++)
 
		{
    
    
 
			SPI_write(0xF0);  // 发送数码管的位 
 
			SPI_write(num[i]);  // 发送数码管的段
 
			NSS_OUTPUT_L();
 
			delay_ms(1);
 
			NSS_OUTPUT_H();   // 锁存的时钟从低到高的变化
 
							// 将移位寄存器中的数据锁存到锁存寄存器中
 
			delay_ms(1000);
 
		}
 
#else 
 
		for(i = 0; i < 4; i++)
 
		{
    
    
 
			SPI_write(0x80 >> i);
 
			SPI_write(num[i+1]);
 
			NSS_OUTPUT_L();
 
			delay_ms(1);
 
			NSS_OUTPUT_H();
 
 
 
		}
 
#endif 
 
	}
 
 
 
	return 0;
 
}

Guess you like

Origin blog.csdn.net/a1379292747/article/details/128554579