一、簡(jiǎn)介
最近因?yàn)轫?xiàng)目需求,需要在一塊板子內(nèi)實(shí)現(xiàn)一個(gè)主機(jī)和五個(gè)從機(jī)的通信;
主機(jī)平臺(tái)選用的是STM32F407VGT6,從機(jī)平臺(tái)選用的是STM32F103C8T6;通信總線選用的是SPI總線。在構(gòu)想是覺(jué)得采用SPI進(jìn)行主從通信會(huì)很簡(jiǎn)單,但在實(shí)際開(kāi)發(fā)的過(guò)程中,各種坑,通信時(shí)而正常時(shí)而混亂。不過(guò)在不斷探究中,也逐漸發(fā)現(xiàn)了,各種問(wèn)題所在,借此記錄下來(lái),希望能幫助一些兄弟在開(kāi)發(fā)中避免一些坑。
本次實(shí)現(xiàn)的平臺(tái)如下:
通信主機(jī):
- 芯片:STM32F103RCT6
- 硬件平臺(tái):野火mini開(kāi)發(fā)板
通信從機(jī):
- 芯片:STM32F103C8T6
- 硬件平臺(tái):淘寶STM32F103C8T6最小系統(tǒng)開(kāi)發(fā)板
軟件:
- HAL庫(kù)
- MDK
- STM32CubeMx
二、開(kāi)發(fā)過(guò)程中遇到的問(wèn)題
以下是我在開(kāi)發(fā)中遇到問(wèn)題:
1. 相同的數(shù)據(jù),每次發(fā)送,主從接收到都是不同的亂碼
開(kāi)發(fā)板之間沒(méi)共地,或者供地接觸不夠好;更換質(zhì)量較好的杜邦線,線材很影響信號(hào)質(zhì)量。
2. 通信不正常,很沒(méi)規(guī)律的不正常
檢查主從機(jī)的SPI外設(shè)配置,接線等。
3. 數(shù)據(jù)出現(xiàn)移位
SPI總線的時(shí)鐘質(zhì)量不好,出現(xiàn)不該出現(xiàn)的高低電平,讓從機(jī)認(rèn)為這是一bit數(shù)據(jù),出現(xiàn)移位寄存器移位,例如原本是8bit數(shù)據(jù),現(xiàn)在由于干擾從機(jī)接收到的可能是9bit或者10bit數(shù)據(jù),而從機(jī)實(shí)際接收到的數(shù)據(jù)只是最先傳入的8bit數(shù)據(jù)。
要保證良好的時(shí)鐘信號(hào),同時(shí)也可以將SPI的數(shù)據(jù)采集觸發(fā)改成時(shí)鐘下降沿觸發(fā)(好像是下降沿的信號(hào)質(zhì)量要比上升沿的信號(hào)質(zhì)量要更好),降低SPI通信速度。
在保證時(shí)鐘的穩(wěn)定的情況下,可通過(guò)復(fù)位從機(jī)的SPI外設(shè)來(lái)解決偶然發(fā)生的數(shù)據(jù)移位問(wèn)題。
4.從機(jī)spi啟動(dòng)比主機(jī)慢
在主機(jī)發(fā)出片選信號(hào)都需要加一段延時(shí),以確保從機(jī)的SPI外設(shè)比主機(jī)先啟動(dòng)。
三、硬件電路接線
NSS片選我們使用軟件控制方式:
所以我們主從機(jī)的SPI通信接線就直接按照手冊(cè)對(duì)接就行。
片選信號(hào)根據(jù)自己需求設(shè)置GPIO口,通過(guò)軟件控制,有效電平和標(biāo)準(zhǔn)SPI協(xié)議保持一樣就好,空閑高,有效低。
四、主從機(jī)SPI外設(shè)配置
4.1、主機(jī)配置
其中只有PA4、PA5、PA6、PA7是我們需要關(guān)注的,PA4是片選腳
4.2、從機(jī)配置
其中只有PA15、PB3、PB4、PB5是我們需要關(guān)注的,PA15是片選管腳。
4.3、接線
PA4 -> PA15(片選Nss)
PA5 -> PB3(SCK)
PA6 -> PB4(MISO)
PA7 -> PB5(MOSI)
五、如何清除移位寄存器
通過(guò)RCC寄存器復(fù)位SPI1外設(shè),在從新初始化SPI1外設(shè)完成移位寄存器清除
if(SPI1->SR != 0x02) //當(dāng)BSY為1時(shí),表示SPI正在忙于通信,但在通信還未開(kāi)始的時(shí)候BSY為1就可以表示移位寄存器存在干擾數(shù)據(jù)
{
//只用通過(guò)RCC復(fù)位整個(gè)SPI外設(shè)后重新初始化,才能清除spi移位寄存器中的殘留數(shù)據(jù)
__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();
MX_SPI1_Init();
printf("SPI復(fù)位,清空移位寄存器殘留數(shù)據(jù)\n");
HAL_Delay(10);
}
六、代碼
6.1、主機(jī)代碼
uint8_t rx_buffer[22]={'1','2','3',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t tx_buffer[22]={0x00,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16};
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("主從測(cè)試開(kāi)始\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//SPI通信
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_Delay(2); //通過(guò)延時(shí)保證從機(jī)SPI外設(shè)比主機(jī)先啟動(dòng)
HAL_SPI_TransmitReceive(&hspi1,tx_buffer,rx_buffer,8,100);
HAL_Delay(10);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
printf("接收到的數(shù)據(jù):");
for(num = 0;num < 8;num++)
{
printf("%#x ",rx_buffer[num]);
}
memset(rx_buffer,0,8);
printf("\n");
HAL_Delay(5000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
//重映射printf函數(shù)
int fputc(int ch,FILE*stream)
{
uint8_t c =ch;
HAL_UART_Transmit(&huart1,&c,1,50);
return ch;
}
6.2、從機(jī)代碼
uint8_t Tx_data[8]={0x87,0xa2,0x41,0x02,0x93,0x04,0x05,0x06};
uint8_t Rx_data[8]={0};
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
bsp_spi_eeror(&hspi1); //通信錯(cuò)誤判斷
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15) == 0) //識(shí)別NSS線(低電平有效)
{
HAL_SPI_TransmitReceive(&hspi1,Tx_data,Rx_data,8,100);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15) == 0){}; //等待 主機(jī) 釋放 片選
printf("spi從機(jī)Rx_dete:");
for(int i=0 ; i < 8;i++)
{
printf("%#x ",Rx_data[i]);
}
memset(Rx_data,0,8);
printf("\n主機(jī)以釋放nss線\n");
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
七、效果展示
左側(cè)為主機(jī)串口顯示,右側(cè)為從機(jī)串口顯示;與程序中的數(shù)據(jù)對(duì)比可發(fā)現(xiàn)收發(fā)數(shù)據(jù)傳輸均正確文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-797121.html
邏輯分析儀顯示數(shù)據(jù):由于中間片選出現(xiàn)了一次高電平干擾,導(dǎo)致后部分的數(shù)據(jù)分析異常,但實(shí)際傳輸?shù)臄?shù)據(jù)是正常的。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-797121.html
到了這里,關(guān)于STM32 HAL庫(kù) SPI主從雙機(jī)通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!