基于SPI总线的数码管显示

main.c

#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)
{
	SPI_init();
	//for循环条件
	/*
	unsigned int i;
	while(1)
	{
	for(i=0;i<10;i++)
	{
     SPI_write(0xF0);
	 SPI_write(num[i]);
	//锁存寄存器从低到高变化
    NSS_OUTPUT_L();
	delay_ms(500);
	NSS_OUTPUT_H();
	}
	}
	*/
	//每位显示不同的值
	//1 2 3 4
	unsigned int i;
 	while(1)
    {
	 for(i=0;i<4;i++)
	 {
     SPI_write(0x80>>i);
	 SPI_write(num[i+1]);
     NSS_OUTPUT_L();
	 delay_ms(1);
	 NSS_OUTPUT_H();
	 delay_ms(100);
	 }
	}
	
	return 0;
}

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->PUPDR &= (~(0x3 << 28));
	// MISO    PE13
	GPIOE->MODER &= (~(0x3 << 26));
	GPIOE->OSPEEDR &= (~(0x3 << 26));
	GPIOE->PUPDR &= (~(0x3 << 26));
	// SCK     PE12	
	GPIOE->MODER &= (~(0x3 << 24));
	GPIOE->MODER |= (0x1 << 24);
	GPIOE->OTYPER &= (~(0x1 << 12));
	GPIOE->OSPEEDR &= (~(0x3 << 24));
	GPIOE->PUPDR &= (~(0x3 << 24));
	// NSS     PE11
	GPIOE->MODER &= (~(0x3 << 22));
	GPIOE->MODER |= (0x1 << 22);
	GPIOE->OTYPER &= (~(0x1 << 11));
	GPIOE->OSPEEDR &= (~(0x3 << 22));
	GPIOE->PUPDR &= (~(0x3 << 22));
	NSS_OUTPUT_L();    // 595芯片的锁存引脚拉低
	SCK_OUTPUT_L();    // SPI的时钟线拉低
}

void SPI_write(unsigned char dat)
{

	//for循环条件
	unsigned char i;
	for(i=0;i<8;i++)
	{
	if(dat&0x1)
	{
	//if判断条件,先发送低位
	//if成立MOSI线写高
	MOSI_OUTPUT_H();
	}
	else
	{
	//else MOSI线写低
	MOSI_OUTPUT_L();
	}	

	//移位寄存器时钟从低到高的变化
    SCK_OUTPUT_L();
	delay_us1(500);
	SCK_OUTPUT_H();
	delay_us1(500);
	dat>>=1;
	}
}

spi.h

#ifndef __SPI_H__
#define __SPI_H__

#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
// MOSI对应的引脚输出高低电平的信号 MOSI---->PE14
#define  MOSI_OUTPUT_H()	do{GPIOE->ODR |= (0x1 << 14);}while(0)
#define  MOSI_OUTPUT_L()    do{GPIOE->ODR &= (~(0x1 << 14));}while(0)

// 对应595芯片的锁存引脚输出高低电平 NSS----->PE11
#define  NSS_OUTPUT_H()	    do{GPIOE->ODR |= (0x1 << 11);}while(0)
#define  NSS_OUTPUT_L()     do{GPIOE->ODR &= (~(0x1 << 11));}while(0)
	
// 时钟信号对应的引脚输出高低电平 SCK----->PE12
#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__

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对你的问题,SPI(Serial Peripheral Interface)是一种串行通信接口,常用于单片机控制外部器件。而数码管可以通过SPI总线来驱动显示。下面是一个简单的SPI驱动数码管的示例代码: ```c #include <avr/io.h> #include <util/delay.h> #define SS_PIN PB2 #define MOSI_PIN PB3 #define SCK_PIN PB5 void spi_init() { DDRB |= (1 << SS_PIN) | (1 << MOSI_PIN) | (1 << SCK_PIN); SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0); // enable SPI, set as master, set prescaler to 16 } void spi_write(uint8_t data) { SPDR = data; while (!(SPSR & (1 << SPIF))); // wait for transmission to complete } void display_number(uint8_t num) { uint8_t digits[4] = {0}; digits[0] = num % 10; digits[1] = (num / 10) % 10; digits[2] = (num / 100) % 10; digits[3] = (num / 1000) % 10; for (int i = 0; i < 4; i++) { PORTB &= ~(1 << SS_PIN); // select the display spi_write(1 << i); // set the digit position spi_write(digits[3 - i]); // send the digit value PORTB |= (1 << SS_PIN); // deselect the display _delay_ms(1); // delay to avoid ghosting } } int main() { spi_init(); while (1) { for (uint8_t i = 0; i < 10000; i++) { display_number(i); _delay_ms(10); } } return 0; } ``` 在这个示例代码中,我们使用AVR微控制器的SPI接口驱动了一个四位数码管。首先,我们需要初始化SPI总线,然后定义一个`display_number`函数用于显示一个数字。在`display_number`函数中,我们将输入的数字拆分成四个位,然后依次将每个位的值通过SPI接口发送给数码管。在主函数中,我们通过循环调用`display_number`函数来显示数字。需要注意的是,由于数码管的刷新速度较慢,所以我们需要在发送完每个数字后加上适当的延时,以避免出现“幽灵”数字。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值