硬件平臺:stm32F10X內部CAN模塊 + TJA1050 + JLink
軟件平臺:Keil 4
一、結果演示

二、接受程序例程
程序涉及的模塊有:
USART:通用同步異步收發器,即串口,用于發送數據至上位機顯示已接收到的數據;
RCC:復位及時鐘控制模塊,用于初始化STM32 外設時鐘及設置CAN總線通信的波特率;
GPIO:通用輸入輸出口;
NVIC:中斷服務程序;
CAN:STM32F10X自帶的CAN通信模塊,F1系列只有1個CAN,F4系列含有2個CAN,大容量的由2個,小容量的只有一個;
Delay:延時等待模塊
Led:用led燈來指示是否正常發送,系統是否工作正常。
RCC
#include "Rcc.h"
void RCC_Init(void)
{
ErrorStatus HSEStartUpStatus; //定義枚舉類型錯誤狀態變量
RCC_DeInit();//復位系統時鐘設置
RCC_HSEConfig(RCC_HSE_ON); //打開外部高速時鐘晶振,使能HSE
/*RCC_HSE_ON 開
_off 關 _bypass hse晶振被外部時鐘旁路*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
/*RCC_WaitForHSEStartUp()返回一個ErrorStatus枚舉值,
success好,error未好*/
if(HSEStartUpStatus == SUCCESS)//HES就緒
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//AHB時鐘(HCLK)=系統時鐘
RCC_PCLK1Config(RCC_HCLK_Div2);
//設置低速AHB時鐘(APB1)為HCLK的2分頻
RCC_PCLK2Config(RCC_HCLK_Div1);
//設置高速AHB時鐘(APB2)=HCLK時鐘
FLASH_SetLatency(FLASH_Latency_2);
//設置FLASH延時周期數為2
//使能領取指緩存
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//設置PLL時鐘源及倍頻系數,為HSE的9倍頻 8MHz * 9 = 72MHz
/*void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)
RCC_PLLSource_HSI_Div2 pll輸入時鐘=hsi/2;
RCC_PLLSource_HSE_Div1 pll輸入時鐘 =hse
RCC_PLLSource_HSE_Div2 pll輸入時鐘=hse/2
RCC_PLLMul_2 ------_16 pll輸入時鐘*2---16
pll輸出時鐘不得超過72MHZ*/
RCC_PLLCmd(ENABLE);
//ENABLE / DISABLE
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待PLL輸出穩定
/*FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG) 檢查指定RCC標志位
返回SET OR RESET
RCC_FLAG_HSIRDY HSI晶振就緒
RCC_FLAG_HSERDY
RCC_FLAG_PLLRDY
RCC_FLAG_LSERDY
RCC_FLAG_LSIRDY.......*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//設置PLL為系統時鐘源
/*void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource) 設置系統時鐘
RCC_SYSCLKSource_HSI
RCC_SYSCLKSource_HSE
RCC_SYSCLKSource_PLLCLK 選HSI HSE PLL 作為系統時鐘*/ while(RCC_GetSYSCLKSource() != 0x08);
//判斷PLL是否是系統時鐘
/*u8 RCC_GetSYSCLKSource(void) 返回用作系統時鐘的時鐘源
0x00:HSI 0x04:HSE 0x08:PLL */
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
RCC_APB2Periph_AFIO , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//U2 U3 時鐘在APB1
//打開GPIO時鐘,復用功能,串口1的時鐘 RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1時鐘
/*void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState)
enable 或 disable apb2 外設時鐘
RCC_APB2Periph_AFIO 功能復用IO 時鐘
RCC_APB2Periph_GPIOA/B/C/D/E GPIOA/B/C/D/E 時鐘
RCC_APB2Periph_ADC1/ADC2 ADC1/2 時鐘
RCC_APB2Periph_TIM1
RCC_APB2Periph_SPI1
RCC_APB2Periph_USART1
RCC_APB2Periph_ALL 全部APB2外設時鐘*/
}
GPIO
#include "GPIO.h"
void MYGPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//GPIO_InitStructure初始化結構體為GPIO_InitTypeDef結構
GPIO_DeInit(GPIOA);
GPIO_StructInit(&GPIO_InitStructure);
//函數:指向結構GPIO_InitTypeDef的指針,待初始化
//CAN TX : A12
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
//CAN TX : A11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
// USART TX :A9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
//GPIO_SPEED:GPIO_SPEED_10MHz/_2MHz/_50MHz 最高輸出速率
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
/*Mode,工作狀態:GPIO_MODE_AIN ----- 模擬輸入
_IN_FLOATING ----- 浮空輸入
_IPD ----- 上拉輸出
_IPU ----- 上拉輸入
_OUT_OD ----- 開漏輸出
_OUT_PP ----- 推挽輸出
_AF_OD ----- 復用開漏輸出
_AF_PP ----- 復用推挽輸出*/
GPIO_Init(GPIOA , &GPIO_InitStructure);
// USART RX :A10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//IO浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//初始化
}
CAN
#include "can.h"
#include "delay.h"
#include "usart.h"
//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回環模式;
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
CAN_DeInit(CAN1);//重置can1為復位狀態
//f10x的庫函數文件里面居然定義了兩個CAN!
CAN_StructInit(&CAN_InitStructure);//復位重置所有的成員變量
CAN_InitStructure.CAN_TTCM=DISABLE;
//enable or disable 時間觸發通訊模式
//非時間觸發通信模式
CAN_InitStructure.CAN_ABOM=DISABLE;
//enable or disable 自動離線管理
//軟件自動離線管理
CAN_InitStructure.CAN_AWUM=DISABLE;
//enable or disable 自動喚醒模式
//睡眠模式通過軟件喚醒(清除CAN->MCR的SLEEP位)
CAN_InitStructure.CAN_NART=ENABLE;
//enable or disable 非自動重傳
//禁止報文自動傳送
CAN_InitStructure.CAN_RFLM=DISABLE;
//enable or disable 接收FIFO 鎖定模式
//報文不鎖定,新的覆蓋舊的
CAN_InitStructure.CAN_TXFP=DISABLE;
//enable or disable 發送FIFO 優先級
//優先級由報文標識符決定
CAN_InitStructure.CAN_Mode= mode;
/*CAN_Mode_Normal CAN硬件工作在正常模式
CAN_Mode_silent CAN硬件工作在靜默模式
CAN_Mode_LoopBack 環回模式
CAN_Mode_Silent_LoopBack 靜默環回模式*/
//模式設置: mode:0,普通模式;1,回環模式;
//設置波特率
CAN_InitStructure.CAN_SJW=tsjw;
/*重新同步跳躍寬度(Tsjw),每位中可以延長或縮短多少個時間單位的上限
為tsjw+1個時間單位
CAN_SJW_1tq 重新同步跳躍寬度為 1 個時間單位
CAN_SJW_2tq
CAN_SJW_3tq
CAN_SJW_4tq*/
CAN_InitStructure.CAN_BS1=tbs1;
/*時間段 1 的時間單位數目 為1--16個時間單位*/
//Tbs1=tbs1+1個時間單位CAN_BS1_1tq ~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2=tbs2;
/*時間段 2 的時間單位數目 為1--8個時間單位*/
//Tbs2=tbs2+1個時間單位CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=brp;
/*設定一個時間單位的長度,范圍是1---1024,實際會減一,這是什么鬼???*/
//分頻系數(Fdiv)為 brp+1 因為實際會減一,所以這里有加一???
CAN_Init(CAN1, &CAN_InitStructure); //初始化CAN1
//can 過濾器設置
CAN_FilterInitStructure.CAN_FilterNumber=0;
//指定待初始化的過濾器,范圍是1---13
//過濾器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
/*CAN_FilterMode_IdMask 標識符屏蔽位模式
CAN_FilterMode_IdList 標識符列表模式*/
//屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
/*過濾器位寬
CAN_FilterScale_Two16bit 2 個 16 位過濾器
CAN_FilterScale_One32bit 1 個 32 位過濾器
因為版本吧 CAN_FilterScale_One32bit 已變為 CAN_FilterScale_32bit*/
//32位寬
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
/*設定過濾器標識符,范圍是0x0000---0xFFFF
32 位位寬時為其高段位,16 位位寬時為第一個*/
//32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
/*設定過濾器標識符,范圍是0x0000---0xFFFF
32 位位寬時為其低段位,16 位位寬時為第二個*/
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
/*設定過濾器屏蔽標識符或者過濾器標識符,范圍是0x0000---0xFFFF
32 位位寬時為其高段位,16 位位寬時為第一個*/
//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
/*設定過濾器屏蔽標識符或者過濾器標識符,范圍是0x0000---0xFFFF
32 位位寬時為其低段位,16 位位寬時為第二個*/
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;
//設定了過濾器指向的FIFO : 0或1
/*CAN_FilterFIFO0 過濾器 FIFO 指向 過濾器x
CAN_FilterFIFO1 過濾器 FIF1 指向 過濾器x */
//過濾器0關聯到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
//激活過濾器0 enable or disable
CAN_FilterInit(&CAN_FilterInitStructure); //濾波器初始化
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
/*enable or disable can中斷
CAN_IT_FMP0 FIFO0消息掛號中斷允許. */
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
//USB 低優先級 or CAN 接收 0 中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 主優先級為1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
// 次優先級為0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
return 0; //配置成功返回 0
}
//如果是開啟了,就有中斷服務函數
void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
int i=0;
can_ack = 1;
CAN_Receive(CAN1, 0, &RxMessage);
for(i=0;i<8;i++)
can_rx[ i ]=RxMessage.Data[ i ];
}
Led
[html] view plain copy 在CODE上查看代碼片派生到我的代碼片
#include "led.h"
//初始化PB12和13為輸出口.并使能這兩個口的時鐘
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口時鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根據設定參數初始化GPIOB
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
}
|