1.實驗目的
使用樹莓派向 STM32 發(fā)送數(shù)據(jù),STM32 收到數(shù)據(jù)后通過串口的方式將數(shù)據(jù)打印到電腦上,同時返回給樹莓派數(shù)據(jù)。樹莓派接收到數(shù)據(jù)后打印在控制臺上。
SPI 的配置為
樹莓派主機
STM32 從機
全雙工
8 bit 傳輸
工作模式 0 :CPOL|CPHA = 00
MSB 優(yōu)先
禁止 CRC 校驗
2.SPI 簡介
SPI(Serial Peripheral Interface,串行外設接口)是 Motorola 公司提出的一種同步串行數(shù)據(jù)傳輸標準
2.1 接口
SPI 接口經常被稱為 4 線串行總線,以主/從方式工作,數(shù)據(jù)傳輸過程由主機初始化,其使用的 4 條信號線分別為:
- SCLK:串行時鐘,用來同步數(shù)據(jù)傳輸,由主機輸出,從機不用配置時鐘
- MOSI:主機輸出從機輸入數(shù)據(jù)線,通常先傳輸 MSB ;
- MISO:主機輸入從機輸出數(shù)據(jù)線,通常先傳輸 LSB ;
- CS:片選線,低電平有效,由主機輸出。
在 SPI 總線上,某一時刻可以出現(xiàn)多個從機,但只能存在一個主機,主機通過片選線來確定要通信的從機。連接是對應相連,如下所示
SCLK-----SCLK
MOSI-----MOSI
MISO-----MISO
CS-----CS
2.2 數(shù)據(jù)傳輸
在一個 SPI 時鐘周期內,會完成如下操作:
- 主機通過 MOSI 線發(fā)送 1 位數(shù)據(jù),從機通過該線讀取這 1 位數(shù)據(jù);
- 從機通過 MISO 線發(fā)送 1 位數(shù)據(jù),主機通過該線讀取這 1 位數(shù)據(jù)。
這是通過移位寄存器來實現(xiàn)的。如下圖所示,主機和從機各有一個移位寄存器,且二者連接成環(huán)。隨著時鐘脈沖,數(shù)據(jù)按照從高位到低位的方式依次移出主機寄存器和從機寄存器,并且依次移入從機寄存器和主機寄存器。當寄存器中的內容全部移出時,相當于完成了兩個寄存器內容的交換。
2.3 時鐘極性和時鐘相位
在 SPI 操作中,最重要的兩項設置就是時鐘極性( CPOL 或 UCCKPL )和時鐘相位( CPHA 或 UCCKPH )。
- CPOL 表示時鐘信號的初始電平的狀態(tài)(就是空閑狀態(tài)),CPOL 為 0 表示時鐘信號初始狀態(tài)為低電平,為 1 表示時鐘信號的初始電平是高電平。
- CPHA 表示在哪個時鐘沿采樣數(shù)據(jù),CPHA 為 0 表示在首個時鐘變化沿采樣數(shù)據(jù),而 CPHA 為 1 則表示在第二個時鐘變化沿采樣數(shù)據(jù)。
主機和從機的發(fā)送數(shù)據(jù)是同時完成的,兩者的接收數(shù)據(jù)也是同時完成的。所以為了保證主從機正確通信,應使得它們的SPI具有相同的時鐘極性和時鐘相位。
2.4 SPI的4種工作模式
由于 CPOL 和 CPHA 都有兩種不同狀態(tài),所以 SPI 分成了 4 種模式。我們在開發(fā)的時候,使用比較多的是模式 0 和模式 3 ,如下表所示
SPI工作模式 | CPOL | CPHA | SCL空閑狀態(tài) | 采樣邊沿 | 采樣時刻 |
---|---|---|---|---|---|
0 | 0 | 0 | 低電平 | 上升沿 | 奇數(shù)邊沿 |
1 | 0 | 1 | 低電平 | 下降沿 | 偶數(shù)邊沿 |
2 | 1 | 0 | 高電平 | 下降沿 | 奇數(shù)邊沿 |
3 | 1 | 1 | 高電平 | 上升沿 | 偶數(shù)邊沿 |
2.5 優(yōu)缺點
優(yōu)點:
- 支持全雙工操作
- 操作簡單
- 數(shù)據(jù)傳輸速率較高
缺點:
- 需要占用主機較多的口線(每個從機都需要一根片選線)
- 只支持單個主機
3.樹莓派部分
3.1 開啟SPI
樹莓派默認是沒有開啟 SPI 的功能的,我們需要手動去開啟一下
在終端輸入
raspi-config
然后跟著下面的圖進行操作(小鍵盤上下左右是選擇,回車是確定)
輸入命令
ls /dev/spi*
出現(xiàn)如下圖的樣子,就是成功打開了
3.2 安裝vscode(可選)
標題是超鏈接,點擊跳轉
3.3 下載bcm支持包
4.STM32部分(只講解SPI和主函數(shù)部分)
4.1 spi.c 中 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 優(yōu)先
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();
}
}
4.2 main.c
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
void SystemClock_Config(void);//函數(shù)聲明,實現(xiàn)在下面
/* 輸出和輸入重定向,主要用于 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};//接收數(shù)據(jù)
uint8_t send_data2[10]={0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6};//發(fā)送數(shù)據(jù)
HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)send_data2, (uint8_t *)data2,10,0xff);//提前將數(shù)據(jù)放進發(fā)送緩存區(qū)
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個字節(jié)的同時,發(fā)送10個字節(jié)出去,等待時間為 65535ms ,超時則不繼續(xù)等待 */
HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)send_data2, (uint8_t *)data2,10,65535);
/* 通過串口發(fā)送給電腦 */
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)
{
}
}
源碼見本文末尾
5.驗證結果
下面是樹莓派的引腳圖
按照下面的方式連接樹莓派與 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
文章來源:http://www.zghlxwxcb.cn/news/detail-633441.html
6.源碼
樹莓派bcm2835-1.71(帶本實驗所需程序)
STM32F407從機SPI使用HAL庫輪詢方式文章來源地址http://www.zghlxwxcb.cn/news/detail-633441.html
到了這里,關于樹莓派(主)與STM32(從)使用SPI通信(持續(xù)更新中)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!