20200305--毕业设计--ESP8266(micropython) 与单片机(Stm32F407)之间通过SPI进行双向数据传输的一种方案,单片机从机模式 ESP8266 主机

背景: 在我的毕业设计中需要单片机将采集到的数据上传到服务器,同时需要接收来自服务器的一些天气信息,我的单片机的型号是 Stm32F407;  ESP8266 刷入了 micropython 的固件,使用python进行开发; 协议是 SPI协议 ESP8266 主机  Stm32F4作为 从机

 单片机侧使用的是 Stm32F407 的硬件 SPI  + DMA 接收发送。    ESP8266 侧使用的也是硬件SPI1 ;  通讯速度应该可以跑满 单片机这一侧的极限速度(42MHz),但是我在测试时候发现数据在40M 就很不稳定了(逻辑分析仪测试,可能是导线有点长)   最终就选择了4MHz.。

整体的这个实现的机制就是在单片机里面设置好 SPI的从机模式  + DMA收发  DMA使用循环模式(自动重复覆盖内存) 然后让ESP8266 侧也是开辟相同大小的 空间,读取发送同步进行;通过控制 单片机侧的开启时间进而实现 两侧的内存的同步(近似的同步  有点类似于镜像)   底层的着四块空间 两两相互可以实现单向映射。

程序实现的介绍

单片机程序的下载地址在这里

ESP8266

import network
#import simple
import time
import json
import machine
from machine import UART,SPI,Pin
machine.freq(160000000)  # 提高主频
#import esps
#esp.osdebug(None) 
CS = Pin(16, Pin.OUT) #片选引脚
#spi = SPI(baudrate=10000000, polarity=1, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12))  #软件模拟
spi = SPI(1, baudrate=4000000, polarity=1, phase=1) #硬件实现

send_buf = bytearray(60)    #创建两个数组大小是 60个byte
recv_buf = bytearray(60)
for i in range(60):
  send_buf[i] =i          # 赋值   实际应用中我们应该是放自己想要传递的数据
cnt =0
print('ok')
while True:
  cnt +=1
  CS.value(0) #
  spi.write_readinto(send_buf,recv_buf) 
  CS.value(1)
  print(recv_buf)
  time.sleep_ms(200)
  print(cnt)

这个是python的代码实现  没啥特殊的  很简单 就是 发送的时候同步进行读取  两个同时进行。

比较难实现的是单片机侧的程序  我们需要配置 SPI  然后 SPI 配置两个DMA的数据流。

声明: 我下面的代码是在其他网友的代码的基础上修改出来的,在这里向原作者致敬



uint8_t SPI_RX_BUFFER[RX_LEN]= {0,}; 
uint8_t SPI_TX_BUFFER[TX_LEN]= {0x1,0x2,0x3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22}; 





/**
  *	@breif  The spi gpio init function.
  * @param  None
  * @retval None
  */  
static void _gpio_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

	GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1); //  CS  Òý½Å  Èí¼þÄ£Äâ
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}



static void spi_dma_init(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	
	/* ??DMA2?? */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	
	/* DMA RX config */
	DMA_InitStructure.DMA_Channel = DMA_Channel_3;                                     // DMA  ͨµÀ
	DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_ADDR;                   //  ÍâÉèµØÖ·
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI_RX_BUFFER;     // ½ÓÊÕ»º³åÇø£¨ÄÚ´æÖеÄÓÐÒ»¸öÊý×飩
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                    //DMA ´«Êä·½Ïò
	DMA_InitStructure.DMA_BufferSize = 100;                                                     //  DMA ´«ÊäµÄÊýÁ¿    Õâ¸öºóÆÚ»¹¿ÉÒÔÔÙ¸Ä
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;             //  ÍâÉèµØÖ·×ÔÔö  È¡Ïû
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                    // ÄÚ´æµØÖ·×ÔÔö  ʹÄÜ
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;     //  ´«ÊäµÄ µ¥Î» £¨byte  8bit£©
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;// ´«ÊäµÄ µ¥Î» £¨byte  8bit£©
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                   //  ÆÕͨģʽ  ´«ÊäÍê³ÉÒ»´Î¾Í×Ô¶¯½áÊø
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                              // ÓÅÏȼ¶ ÖеÈ
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                   //²»Ê¹Óà FIFO
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;             //
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;              //
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;        //
	DMA_Init(DMA2_Stream2, &DMA_InitStructure);                                            //³õʼ»¯
	                                                                                                                   //
	/* DMA TX Config */                                                                                      //
	DMA_InitStructure.DMA_Channel = DMA_Channel_3;                                     // DMA  ͨµÀ
	DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_ADDR;                   //   ÍâÉèµØÖ· 
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI_TX_BUFFER;     // ½ÓÊÕ»º³åÇø£¨ÄÚ´æÖеÄÓÐÒ»¸öÊý×飩
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                    // DMA ´«Êä·½Ïò 
	DMA_InitStructure.DMA_BufferSize = 100;                                                     //  DMA ´«ÊäµÄÊýÁ¿    Õâ¸öºóÆÚ»¹¿ÉÒÔÔÙ¸Ä
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;             //  ÍâÉèµØÖ·×ÔÔö  È¡Ïû
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                    // ÄÚ´æµØÖ·×ÔÔö  ʹÄÜ
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;     //   ´«ÊäµÄ µ¥Î» £¨byte  8bit£© 
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;// ´«ÊäµÄ µ¥Î» £¨byte  8bit£©
//	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                   //   ÆÕͨģʽ  ´«ÊäÍê³ÉÒ»´Î¾Í×Ô¶¯½áÊø 
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                   //   ÆÕͨģʽ  ´«ÊäÍê³ÉÒ»´Î¾Í×Ô¶¯½áÊø 
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                              // ÓÅÏȼ¶ ÖеÈ
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                   //
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;             //
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;              //
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;        //
	DMA_Init(DMA2_Stream3, &DMA_InitStructure);                                            //³õʼ»¯
}



/**
  *	@breif  The spi init function.
  * @param  None
  * @retval None
  */  
void bsp_spi_init(void)
{
	SPI_InitTypeDef SPI_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
	_gpio_init();
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, ENABLE);   
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, DISABLE);  

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // Ë«ÏßÈ«Ë«¹¤
	SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;                            // Ö÷»úģʽ
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                       //8bit  λ¿í
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                            //SCK  ¿ÕÏÐʱÖÓΪ¸ßµçƽ
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                         // µÚ¶þ¸öʱÖÓ±ßÔµ  ²¶»ñ
	SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;                                //NSSʹÓõÄÊÇÈí¼þÄ£Äâ
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; // SPI ʱÖӵķÖƵϵÊý 
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                        //  MSB £¨ ¸ßλÔÚÇ°£©
	SPI_InitStructure.SPI_CRCPolynomial = 7;                             
	SPI_Init(SPI1, &SPI_InitStructure);

	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);  
	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
	spi_dma_init();
	SPI_Cmd(SPI1, ENABLE);
	
	SPI_I2S_ClearITPendingBit(SPI1, SPI_I2S_IT_RXNE);
  SPI1_SetSpeed(SPI_BaudRatePrescaler_2);    ///  µ÷ÕûËÙ¶È   ËÙ¶ÈÈ«¿ª  ʵ²â´óÔ¼ÊÇ 42M Hz
}



/* ?????DMA?? */

/**
  *	@breif  The spi dma trans function.
  * @param  rx_buf -- the point of rx buffer
  * @param  tx_buf -- the point of tx buffer
  * @elngth length -- the size of data.
  * @retval None
  */  
void spi_trans(uint8_t *rx_buf,     
			   uint8_t *tx_buf,    
			   uint16_t length)    
{

	DMA_Cmd(DMA2_Stream2, DISABLE);                                                         //  ¹Ø±Õ DMA 
	DMA_Cmd(DMA2_Stream3, DISABLE);                                                         //¹Ø±Õ DMA 
                                                                                                                      //
	DMA_SetCurrDataCounter(DMA2_Stream2, (uint16_t)length);                          //  ÉèÖà DMAµÄ´«Êä²ÎÊý 
	DMA_SetCurrDataCounter(DMA2_Stream3, (uint16_t)length);                          // ÉèÖà DMAµÄ´«Êä²ÎÊý 
	                                                                                                                    //
	DMA2_Stream2->M0AR = (uint32_t)rx_buf;                                                     //  ÉèÖà ÄÚ´æµÄÆðʼµØÖ·
	DMA2_Stream3->M0AR = (uint32_t)tx_buf;                                                     //   ÉèÖà ÄÚ´æµÄÆðʼµØÖ·
                                                                                                                      //
	SPI1->DR;                                                                                                    //
	                                                                                                                    //  ¼Ù×°¶ÁÈ¡Çå³þ ±ê־λ 
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);            //   µÈ´ýÏÈÇ°µÄ·¢ËÍÍê±Ï
	                                                                                                                    //
	DMA_Cmd(DMA2_Stream2, ENABLE);                                                           //  ´ò¿ª DMA  ¿ªÊ¼·¢ËÍ
	DMA_Cmd(DMA2_Stream3, ENABLE);                                                           //  ´ò¿ª DMA  ¿ªÊ¼½ÓÊÕ
	                                                                                                                    //
//	while( DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_TCIF3) == RESET);   //  ×èÈûʽ  ÔÚÕâÀïµÈ´ýÊý¾Ý·¢ËÍÍê
//	while( DMA_GetFlagStatus(DMA2_Stream2, DMA_FLAG_TCIF2) == RESET);   //   ÕâÀï·¢ËÍËٶȿÉÒԷdz£¿é  ×èÈûÒ²¿ÉÒÔ 
//	                                                                                                                    //
//	DMA_Cmd(DMA2_Stream2, DISABLE);                                                         // ·¢ËÍÍê  ¹Ø±Õ DMA
//	DMA_Cmd(DMA2_Stream3, DISABLE);	                                                        //
//	                                                                                                                    //
//	DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);                                    //   Çå³þ±ê־λ
//	DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_TCIF3);                                    //
}

这个是主体代码

扫描二维码关注公众号,回复: 11380943 查看本文章

这一部分是 整体的初始化函数  主要是 SPI协议相关的参数的设置 以及 一些设置。

这里是一些GPIO的 复用设置   这里要注意  就是 CS引脚  要选择硬件 CS引脚

DMA 初始化前半部分  这是 接收DMA的 部分

这一部分是  发送DMA 的程序   相比较于原作者的代码 我的代码修改了 DMA的传输模式 换成了  循环模式

  最后一部分的代码是  开启DMA传输的函数 

再从机模式下  我们设置的时钟都不起作用  时钟是主机提供的,  所以这边可以不管时钟的设置 

在这里我的程序中使用的 IO 口是 PA4 PA5 PA6 PA7

这是 SPI.h 的头文件

void bsp_spi_init(void);
void spi_trans_read(uint8_t *rx_buf,
					uint8_t *tx_data,
					uint16_t length);
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler);


#define RX_LEN 		    	(uint8_t)60
#define TX_LEN          (uint8_t)60

#define SPI1_DR_ADDR    (uint32_t)0x4001300C



extern uint8_t SPI_RX_BUFFER[RX_LEN];
extern uint8_t SPI_TX_BUFFER[TX_LEN]; 

还有一点小的心得就是 我们要注意初始化的时机,就是为了防止出现错位的情况 我们需要在 CS 引脚 是高电平的时候 开启传输

ESP8266 那一侧不是DMA 所以这个的波形不是很紧凑   不过速度也还可以  比串口肯定是快多了

10M的速度也是非常稳定的   不过 用不到那么快的速度。  而且我是用导线连接的  干扰很大 

20 M 的速度时候 CS 引脚就会收到很大的干扰

剩下的就是我们去  自己定义想要传输的数据了   准备好的数据放在内存中就可以了  等待 主机发起一次传输  双方就把数据进行了一次的交换。  再次吐槽 ESP8266 的一个半串口太坑了 

代码的下载链接在这里  

猜你喜欢

转载自blog.csdn.net/weixin_41534481/article/details/104681882