赞
踩
使用树莓派向 STM32 发送数据,STM32 收到数据后通过串口的方式将数据打印到电脑上,同时返回给树莓派数据。树莓派接收到数据后打印在控制台上。
SPI 的配置为
树莓派主机
STM32 从机
全双工
8 bit 传输
工作模式 0 :CPOL|CPHA = 00
MSB 优先
禁止 CRC 校验
SPI(Serial Peripheral Interface,串行外设接口)是 Motorola 公司提出的一种同步串行数据传输标准
SPI 接口经常被称为 4 线串行总线,以主/从方式工作,数据传输过程由主机初始化,其使用的 4 条信号线分别为:
在一个 SPI 时钟周期内,会完成如下操作:
在 SPI 操作中,最重要的两项设置就是时钟极性( CPOL 或 UCCKPL )和时钟相位( CPHA 或 UCCKPH )。
由于 CPOL 和 CPHA 都有两种不同状态,所以 SPI 分成了 4 种模式。我们在开发的时候,使用比较多的是模式 0 和模式 3 ,如下表所示
SPI工作模式 | CPOL | CPHA | SCL空闲状态 | 采样边沿 | 采样时刻 |
---|---|---|---|---|---|
0 | 0 | 0 | 低电平 | 上升沿 | 奇数边沿 |
1 | 0 | 1 | 低电平 | 下降沿 | 偶数边沿 |
2 | 1 | 0 | 高电平 | 下降沿 | 奇数边沿 |
3 | 1 | 1 | 高电平 | 上升沿 | 偶数边沿 |
优点:
缺点:
树莓派默认是没有开启 SPI 的功能的,我们需要手动去开启一下
在终端输入
raspi-config
然后跟着下面的图进行操作(小键盘上下左右是选择,回车是确定)
输入命令
ls /dev/spi*
出现如下图的样子,就是成功打开了
标题是超链接,点击跳转
/* SPI1 引脚初始化,会在HAL_SPI_Init的时候调用*/ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(spiHandle->Instance==SPI1) { __HAL_RCC_SPI1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**SPI1 引脚配置 PA4 ------> SPI1_NSS PA5 ------> SPI1_SCK PA6 ------> SPI1_MISO PA7 ------> SPI1_MOSI */ GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } } /* SPI1 配置初始化 */ void MX_SPI1_Init(void) { hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_SLAVE;// 从机 hspi1.Init.Direction = SPI_DIRECTION_2LINES;// 全双工 hspi1.Init.DataSize = SPI_DATASIZE_8BIT;//8 bit 传输 hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;//CPOL = 0 hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;//CPHA = 0 hspi1.Init.NSS = SPI_NSS_HARD_INPUT;//片选硬件输入 hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;//MSB 优先 hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//禁止 CRC 校验 hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK)//判断是否初始化成功 { Error_Handler(); } }
#include "main.h" #include "spi.h" #include "usart.h" #include "gpio.h" #include "stdio.h" void SystemClock_Config(void);//函数声明,实现在下面 /* 输出和输入重定向,主要用于 printf 串口输出 */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff); return ch; } int fgetc(FILE *f) { uint8_t ch = 0; HAL_UART_Receive(&huart1, &ch, 1, 0xffff); return ch; } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init();//串口初始化 MX_SPI1_Init();//SPI1初始化 HAL_Delay(1000); uint8_t data2[10]={0};//接收数据 uint8_t send_data2[10]={0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6};//发送数据 HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)send_data2, (uint8_t *)data2,10,0xff);//提前将数据放进发送缓存区 while (1) { HAL_GPIO_WritePin(Start_GPIO_Port,Start_Pin,GPIO_PIN_RESET); HAL_Delay(100); HAL_GPIO_WritePin(Start_GPIO_Port,Start_Pin,GPIO_PIN_SET); /* 接收10个字节的同时,发送10个字节出去,等待时间为 65535ms ,超时则不继续等待 */ HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)send_data2, (uint8_t *)data2,10,65535); /* 通过串口发送给电脑 */ for(int i=0;i<10;i++) { printf("0x%02X\n",data2[i]);//指定为以16进制的形式格式化输出 } HAL_Delay(2000);//延时2s } } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } } /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { __disable_irq(); while (1) { } }
源码见本文末尾
下面是树莓派的引脚图
按照下面的方式连接树莓派与 STM32 的引脚
树莓派--------STM32
MOSI/#10--------PA7
MISO/#9----------PA6
SCLK/#11--------PA5
GND---------------GND
cd “/home/pi/SPI_test/bcm2835-1.71/examples/spi/” && gcc *.c -o spi && "/home/pi/SPI_test/bcm2835-1.71/examples/spi/"spi
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。