SPI实验

工作原理:
在这里插入图片描述
实现代码:

#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__

#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();

}

#include "gpio.h"
#include "uart4.h"
#include "command.h"
#include "beep.h"
#include "key-TI.h"
#include "si7006.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++);
}
void led_init(void)
{
	RCC_MP_AHB4ENSETR |= (0x3 << 4);
	// gpio_init_t init = {GPIO_OUTPUT,GPIO_PP,LOW_SPEED,NOPUPD};
	/*
	gpio_init_t init;
	init.mode = GPIO_OUTPUT;
	init.type = GPIO_PP;
	init.speed = LOW_SPEED;
	init.pupd = NOPUPD;
*/
	gpio_init_t gpio_init = {
		.mode = GPIO_OUTPUT,
		.type = GPIO_PP,
		.speed = LOW_SPEED,
		.pupd = NOPUPD,
	};
	hal_gpio_init(GPIOE, &gpio_init, GPIO_PIN_10);
	hal_gpio_init(GPIOF, &gpio_init, GPIO_PIN_10);
	hal_gpio_init(GPIOE, &gpio_init, GPIO_PIN_8);
}

void led_flash(void)
{
	hal_gpio_write(GPIOE, GPIO_PIN_10, GPIO_SET);
	delay_ms(500);
	hal_gpio_write(GPIOE, GPIO_PIN_10, GPIO_RESET);
	delay_ms(500);
}
int num[10] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6};
int main(void)
{
	unsigned char i;
	SPI_init();
	while(1)
	{
#if 1
		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;
}

实验现象:
在这里插入图片描述

### SPI 实验设置与教程 对于希望深入了解 SPI(Serial Peripheral Interface)并进行相关实验的学习者来说,可以从基础概念入手,并逐步实践具体的硬件配置和编程方法。以下是关于如何搭建 SPI 实验环境以及一些推荐的资源。 #### 1. **SPI 的基本原理** SPI 是一种同步串行通信接口,用于短距离通信,主要应用在微控制器与其外围设备之间。它通常涉及四条信号线:MOSI(Master Out Slave In)、MISO(Master In Slave Out)、SCLK(Serial Clock),以及 SS/CS(Slave Select)。这些线路共同构成了主机与从机之间的数据传输通道[^3]。 #### 2. **实验所需材料** 为了开展 SPI 实验,可以准备以下组件: - 微控制器开发板(如 Arduino、Raspberry Pi 或 Particle 设备) - 支持 SPI 协议的外设模块(如 ADC 芯片 MCP3008、OLED 显示屏等) - 面包板及跳线 - USB 数据线连接至计算机 #### 3. **基于 Particle 开发板的 SPI 设置** 如果使用的是 Particle 系列开发板,则可以通过其官方文档找到有关 SPI 初始化和支持的信息。例如,在某些情况下可能需要调整 WiFi 凭据或其他网络参数以便于调试工作流[^1]。然而需要注意的是,Particle 官方资料更侧重物联网功能而非纯粹的低层协议教学;因此建议补充其他来源的知识点作为辅助参考资料。 另外提到的一个重要主题是如何利用直接内存访问(DMA)技术提高数据吞吐量效率。这方面的指导可以在Leaflabs提供的《SPI+DMA 教程》中获得更为详尽的说明,该文章不仅涵盖了Maple平台上的具体实现细节,还介绍了dma.h类的相关定义及其用途[^2]。 #### 4. **代码示例** 下面给出一段简单的 Python 示例程序片段展示如何读取来自模拟数字转换器的数据: ```python import spidev import time # 创建 spi 对象实例化 spi = spidev.SpiDev() spi.open(0, 0) def readadc(channel): r = spi.xfer2([1,(8+channel)<<4,0]) adcout = ((r[1]&3) << 8) + r[2] return adcout try: while True: value = readadc(0) print(f"ADC Value: {value}") time.sleep(0.5) except KeyboardInterrupt: pass finally: spi.close() ``` 此脚本展示了通过 `spidev` 库控制 Linux 平台下的 SPI 总线交互过程,其中包含了打开指定端口、发送命令帧序列以及解析返回结果等功能调用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值