一、功能描述:
如上圖所示,實(shí)現(xiàn)了以下功能:
1.兩塊stm32單片機(jī)通過CAN控制器與收發(fā)器進(jìn)行半雙工通信;
2.stm32主機(jī)通過檢測按鍵,切換不同的模式,將不同模式的case值發(fā)送給stm32從機(jī);
3.stm32從機(jī)根據(jù)收到的case值,控制步進(jìn)電機(jī)進(jìn)行不同的運(yùn)動操作;
4.OLED用于顯示收發(fā)內(nèi)容與按鍵狀態(tài)等信息。
二、CAN總線概述
1.CAN總線協(xié)議
????????CAN總線(Controller Area Network)是一種串行通信協(xié)議,最初是由德國Bosch公司在1983年為汽車應(yīng)用而開發(fā)的。然而,由于其高效、可靠的性能,CAN總線已經(jīng)被廣泛用于各種領(lǐng)域,包括工業(yè)控制、醫(yī)療設(shè)備、軍事應(yīng)用等。(來源:ChatGPT)
以下是CAN總線的一些關(guān)鍵特點(diǎn)和特性:
-
串行通信: CAN總線使用串行通信,通過兩根導(dǎo)線進(jìn)行數(shù)據(jù)傳輸,即CAN_H和CAN_L。這種方式有助于減小線纜數(shù)量,降低成本,同時提高系統(tǒng)的可靠性。
-
實(shí)時性: CAN總線的設(shè)計目標(biāo)之一是提供高實(shí)時性,適用于需要及時響應(yīng)和同步的應(yīng)用。這使得它特別適用于汽車電子系統(tǒng)等需要高度協(xié)同工作的場景。
-
多主機(jī)網(wǎng)絡(luò): CAN總線支持多主機(jī)網(wǎng)絡(luò),允許多個節(jié)點(diǎn)同時發(fā)送和接收數(shù)據(jù)。這使得多個電子控制單元(ECU)能夠并行工作,促進(jìn)系統(tǒng)的分布式控制。
-
抗干擾性: CAN總線具有很強(qiáng)的抗干擾能力。它采用不同的電壓水平來表示0和1,這使得CAN總線對電磁干擾具有一定的容忍性。
-
錯誤檢測和冗余: CAN總線使用CRC(循環(huán)冗余校驗(yàn))來檢測傳輸中的錯誤,并能夠在數(shù)據(jù)幀中添加冗余位,以提高錯誤檢測和糾正的能力。
-
消息優(yōu)先級: CAN總線使用標(biāo)識符來給消息分配優(yōu)先級。低標(biāo)識符的消息擁有更高的優(yōu)先級,這有助于確保緊急消息能夠在較短的時間內(nèi)被傳輸。
-
靈活性: CAN總線的協(xié)議允許節(jié)點(diǎn)通過標(biāo)識符來識別和篩選消息,從而實(shí)現(xiàn)更靈活的通信結(jié)構(gòu)。
????????總體而言,CAN總線是一種可靠、高效的通信協(xié)議,特別適用于需要實(shí)時性和多節(jié)點(diǎn)通信的應(yīng)用場景。在汽車領(lǐng)域,它被廣泛用于車輛內(nèi)部的電子控制系統(tǒng),如發(fā)動機(jī)控制單元(ECU)、制動系統(tǒng)、空調(diào)系統(tǒng)等。
2.CAN總線網(wǎng)絡(luò)
????????CAN總線?絡(luò)主要掛在CAN_H和CAN_L,各個節(jié)點(diǎn)通過這兩條線實(shí)現(xiàn)信號的串?差分傳輸,為了避免信號的反射和?擾,還需要在CAN_H和CAN_L之間接上120歐姆的終端電阻。為什么是120Ω,因?yàn)殡娎|的特性阻抗為120Ω,為了模擬?限遠(yuǎn)的傳輸線。
3.CAN總線信號
????????CAN總線采?不歸零碼位填充技術(shù),信號有兩種不同狀態(tài),分別為隱形電平和顯性電平。CAN的數(shù)據(jù)總線有兩條CAN_H和CAN_L,當(dāng)沒有數(shù)據(jù)發(fā)送時,兩條線的電平?樣都為2.5V,稱為靜電平,也就是隱性電平。當(dāng)有信號發(fā)送時,CAN_H的電平升?1V,即3.5V,CAN_L的電平降低1V即1.5V,此時為顯性電平。信號每?次傳輸完后不需要返回到顯性電平。
定義 | 總線電平 | 邏輯電平 |
CAN_H-CAN_L<0.5V | 隱性電平 | 1 |
CAN_H-CAN_L>0.9V | 顯性電平 | 0 |
4.CAN總線工作原理
????????①CAN總線沒有主從節(jié)點(diǎn)之分,所有CAN總線上的節(jié)點(diǎn)都是地位等價的。當(dāng)CAN總線上的?個節(jié)點(diǎn)發(fā)送數(shù)據(jù)時,它以報?的形式?播給?絡(luò)中的?所有節(jié)點(diǎn);這樣對于每個節(jié)點(diǎn)來說,?論數(shù)據(jù)是否發(fā)給??,都對其進(jìn)?接收。
????????②CAN總線每組報?開頭的11位字符為標(biāo)識符,定義了報?的優(yōu)先級;在同?個總線中,標(biāo)識符是唯?的,不可能有兩個節(jié)點(diǎn)發(fā)送具有相同標(biāo)識符的報?。當(dāng)然接收節(jié)點(diǎn)也會根據(jù)標(biāo)識符來判斷是否接收這幀信息,?般稱這項(xiàng)技術(shù)為報?濾波技術(shù)。
????????③CAN總線接收節(jié)點(diǎn)可以通過遠(yuǎn)程數(shù)據(jù)請求發(fā)送遠(yuǎn)程幀請求發(fā)送節(jié)點(diǎn)發(fā)送相應(yīng)的數(shù)據(jù),回應(yīng)節(jié)點(diǎn)傳送的數(shù)據(jù)幀與請求數(shù)據(jù)的遠(yuǎn)程幀具有相同的標(biāo)識符。(接收校對標(biāo)識符)
????????④CAN總線的優(yōu)先權(quán)由發(fā)送數(shù)據(jù)報?中的標(biāo)識符決定報?占?總線的優(yōu)先權(quán);標(biāo)識符越?,優(yōu)先權(quán)越?。
????????⑤CAN總線的仲裁機(jī)制:只要總線空閑,任何節(jié)點(diǎn)都可以向總線發(fā)送報?。如果有兩個或兩個以上的節(jié)點(diǎn)同時發(fā)送報?,就會引起總線訪問碰撞。通過使?標(biāo)識符逐位仲裁可以解決這個碰撞問題。?且當(dāng)具有相同標(biāo)識符的數(shù)據(jù)幀和遠(yuǎn)程幀同時發(fā)送時,數(shù)據(jù)幀優(yōu)先于遠(yuǎn)程幀。
????????⑥?前CAN總線通信協(xié)議僅僅包括OSI七層互聯(lián)參考模型中的數(shù)據(jù)鏈路層和物理層。
三、代碼實(shí)操
1.配置CAN總線:
? ? ? ? ①初始化GPIO兩個收發(fā)引腳(stm32f103c8t6只有一個CAN1控制器,固定引腳)
? ? ? ? ②初始化NVIC中斷向量表優(yōu)先級
? ? ? ? ③初始化CAN相關(guān)參數(shù)配置
? ? ? ? ④初始化CAN過濾器(篩選器)
void CAN_init() {
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE); //使能時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
/**********************************GPIO****************************************************************/
//CAN_TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PB9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出,TX
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化PB9
//CAN_RX
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//PB8
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //復(fù)用推挽輸出,RX
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化PB8
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
/***********************************CAN工作模式初始化****************************************************/
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
//時間觸發(fā)模式
CAN_InitStructure.CAN_TTCM = DISABLE;
//自動離線管理
CAN_InitStructure.CAN_ABOM = ENABLE;
//自動喚醒模式
CAN_InitStructure.CAN_AWUM = ENABLE;
//報文自動重傳 (0為啟用)
CAN_InitStructure.CAN_NART = DISABLE;
//FIFO溢出時報文覆蓋原文件
CAN_InitStructure.CAN_RFLM = DISABLE;
//報文發(fā)送優(yōu)先級取決于郵箱先后
CAN_InitStructure.CAN_TXFP = DISABLE;
//工作模式:普通模式
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
//設(shè)置CAN波特率 (1MHz)
CAN_InitStructure.CAN_SJW = CAN_SJW_4tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_5tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
CAN_InitStructure.CAN_Prescaler = 5;
//初始化CAN
CAN_Init(CAN1,&CAN_InitStructure);
//接受到一條報文即可產(chǎn)生中斷
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
/***********************************NVIC****************************************************************/
//CAN NVIC 配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//搶占優(yōu)先級0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子優(yōu)先級0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化NVIC寄存器
//使能接收中斷
/*************************************CAN過濾器******************************************************/
//使能過濾器
CAN_FilterInitStruct. CAN_FilterActivation = ENABLE;
//過濾器0關(guān)聯(lián)到FIFO0
CAN_FilterInitStruct.CAN_FilterFIFOAssignment = CAN_FilterFIFO0;
//屏蔽濾波功能
CAN_FilterInitStruct.CAN_FilterNumber = 0;
//標(biāo)識符屏蔽位模式
CAN_FilterInitStruct.CAN_FilterMode = CAN_FilterMode_IdList;
//32位寄存器
CAN_FilterInitStruct.CAN_FilterScale = CAN_FilterScale_32bit;
//高16位
//接收ID為CAN_EXID1的消息,使用拓展位以及遙控幀
CAN_FilterInitStruct.CAN_FilterIdHigh = ( ((CAN_EXID1<<3)|CAN_ID_EXT|CAN_RTR_DATA) & 0xffff0000 )>>16;
//低16位
CAN_FilterInitStruct.CAN_FilterIdLow = ( ((CAN_EXID1<<3)|CAN_ID_EXT|CAN_RTR_DATA) & 0x0000ffff );
//屏蔽位高16位
//屏蔽ID為CAN_EXID2的消息,使用拓展位以及數(shù)據(jù)幀
CAN_FilterInitStruct.CAN_FilterMaskIdHigh = ( ((CAN_EXID2<<3)|CAN_ID_EXT|CAN_RTR_DATA) & 0xffff0000 )>>16;
//屏蔽位低16位
CAN_FilterInitStruct.CAN_FilterMaskIdLow = ( ((CAN_EXID2<<3)|CAN_ID_EXT|CAN_RTR_DATA) & 0x0000ffff );
//初始化過濾器
CAN_FilterInit(&CAN_FilterInitStruct);
}
2.CAN收發(fā)函數(shù)
//發(fā)送
void CAN_TransmitData()
{
extern uint8_t cntkey;
extern CanTxMsg TX_Message;
TX_Message.Data[0]=cntkey;
TX_Message.DLC = 8; //數(shù)據(jù)包長度為8字節(jié)
TX_Message.IDE = CAN_ID_EXT;
TX_Message.ExtId = CAN_EXID1;
TX_Message.RTR = CAN_RTR_DATA;
TX_Message.StdId = 0;
CAN_Transmit(CAN1,&TX_Message);
}
//接收中斷,和USB共用
void USB_LP_CAN1_RX0_IRQHandler()
{
if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)!=RESET)
{
CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
CAN_Receive(CAN1,CAN_FIFO0,&RX_Message);
GPIOC->ODR^=GPIO_Pin_13;
CAN_RX_Stat = 1;
}
}
3.主函數(shù)main
/**
******************************************************************************
* @file main.c
* @author ZYS
* @version V1.0
* @date 2024-01-05
* @brief can通信步進(jìn)電機(jī)協(xié)同控制
******************************************************************************
*/
#include "zys_headfile.h"
CanTxMsg TX_Message;
CanRxMsg RX_Message;
extern bool CAN_RX_Stat;
uint8_t rx_flag=0;
uint8_t cntkey;
uint8_t rx_data;
uint8_t keynum = 0;
uint8_t speed1 = 4;
uint8_t dir1 = 0;
uint8_t speed2 = 4;
uint8_t dir2 = 0;
int main ( void )
{
/* 初始化 */
Motor_Init();
USART1_Config (); //初始化串口1
CPU_TS_TmrInit(); //初始化DWT計數(shù)器,用于延時函數(shù)
LED_GPIO_Config(); //初始化 LED 燈
OLED_Init();
key_init();
//初始化CAN配置
CAN_init();
for(uint8_t i=0;i<8;i++)
{
TX_Message.Data[i]=0;
}
while ( 1 )
{
OLED_ShowString(4,1,"spd:");
OLED_ShowString(3,1,"dir:");
OLED_ShowNum(4,6,speed1,2);//speed1
OLED_ShowNum(3,6,dir1,1);
OLED_ShowNum(4,8,speed2,2);
OLED_ShowNum(3,8,dir2,1);
OLED_ShowString(1,1,"cntkey:");
OLED_ShowString(2,1,"keynum:");
OLED_ShowNum(1,9,cntkey,1);
OLED_ShowNum(2,9,keynum,1);
OLED_ShowString(2,12,"rx:");
OLED_ShowNum(2,16,rx_data,1);
OLED_ShowString(1,12,"tx:");
OLED_ShowNum(1,16,TX_Message.Data[0],1);
CAN_TransmitData();
keynum = Key_GetNum();
if(keynum == 1){cntkey ++;}
if(cntkey == 6){cntkey = 0;}
rx_data = RX_Message.Data[0];
switch (rx_data){
case 0: dir1 = 0;dir2 = 0;break;
case 1: dir1 = 1;dir2 = 1;break;
case 2: dir1 = 1;dir2 = 0;break;
case 3: dir1 = 0;dir2 = 1;break;
case 4: speed1 = 20;speed2 = 20;break;
case 5: speed1 = 4;speed2 = 4;break;
default: cntkey = 0;break;
}
if(dir1){MotorGO1(speed1);}
else{MotorBack1(speed1);}
if(dir2){MotorGO2(speed1);}
else{MotorBack2(speed1);}
}
}
四、實(shí)物演示
文章來源:http://www.zghlxwxcb.cn/news/detail-805822.html
STM32基于CAN總線通信的多個步進(jìn)電機(jī)協(xié)同控制文章來源地址http://www.zghlxwxcb.cn/news/detail-805822.html
到了這里,關(guān)于STM32基于CAN總線協(xié)議控制步進(jìn)電機(jī)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!