第十章AT32F403A替换stm32f105双 can通讯测试
前言
此文章是修改stm32f105的工程,可在AT32F403A上跑双can通讯功能。
硬件
硬件方面使用的是自己画的板子,使用的AT32F403ARCT7,外设方面有USART2、USART3、CAN1、CAN2、SPI、IIC、USB、SDIO;USART接的是max485的芯片;CAN的收发芯片都是SIT1050(芯力特国产品牌,可替换tja1050);SPI的是接了一颗W25Q128,16M的容量;IIC接的是一颗AT24C04;SDIO可插SD卡。仿真口以及串口1则使用的ATLINK的接口定义,直接使用ATLINK插上即可。USART2和USART3的485芯片,可以通过跳线帽对接起来;CAN1和CAN2也是一样。
本测试是使用的板子上的CAN1和CAN2互发信息,所以右上角的用跳线帽把H1和H2对接,L1和L2对接。
软件
测试使用的软件是stm32f105的3.5标准库的工程代码。由于AT32F403A的CAN2和stm32f105的CAN2是存在差异的,AT32的CAN1和CAN2是相互独立的,滤波器也是相互独立的,而f105的CAN2和CAN1有关联,所以必须修改库才能使用CAN2。
系统时钟差异:AT32时钟配置是可以直接替换f103的,但是f103和f105的系统时钟是不一样的,所以需要配置系统时钟的和f103的一样的。
void RCC_Config(void)
{
u8 HSEStartUpStatus = 0;
RCC_DeInit(); //初始化
RCC_HSEConfig(RCC_HSE_ON); //时能外部晶振
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
RCC_PCLK2Config(RCC_HCLK_Div1); //APB2预分频 /* PCLK2 = HCLK 最大72Mhz*/
RCC_PCLK1Config(RCC_HCLK_Div2); //APB1预分频 = 72Mhz / 2 = 36MHz /* PCLK1 = HCLK/4 最大36MHz*/
RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB预分频 /* HCLK = SYSCLK */
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9); /* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLCmd(ENABLE); /* Enable PLL */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) /* Wait till PLL is ready */
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* Select PLL as system clock source */
while(RCC_GetSYSCLKSource() != 0x08) /* Wait till PLL is used as system clock source */
{
}
}
}
中断号差异:
CAN滤波器初始化函数:
void CAN_FilterInit(CAN_TypeDef* CANx,CAN_FilterInitTypeDef* CAN_FilterInitStruct) //AT32 CAN2
{
uint32_t filter_number_bit_pos = 0;
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_FILTER_NUMBER(CAN_FilterInitStruct->CAN_FilterNumber));
assert_param(IS_CAN_FILTER_MODE(CAN_FilterInitStruct->CAN_FilterMode));
assert_param(IS_CAN_FILTER_SCALE(CAN_FilterInitStruct->CAN_FilterScale));
assert_param(IS_CAN_FILTER_FIFO(CAN_FilterInitStruct->CAN_FilterFIFOAssignment));
assert_param(IS_FUNCTIONAL_STATE(CAN_FilterInitStruct->CAN_FilterActivation));
filter_number_bit_pos = ((uint32_t)1) << CAN_FilterInitStruct->CAN_FilterNumber;
/* Initialisation mode for the filter */
CANx->FMR |= FMR_FINIT;
/* Filter Deactivation */
CANx->FA1R &= ~(uint32_t)filter_number_bit_pos;
/* Filter Scale */
if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_16bit)
{
/* 16-bit scale for the filter */
CANx->FS1R &= ~(uint32_t)filter_number_bit_pos;
/* First 16-bit identifier and First 16-bit mask */
/* Or First 16-bit identifier and Second 16-bit identifier */
CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow);
/* Second 16-bit identifier and Second 16-bit mask */
/* Or Third 16-bit identifier and Fourth 16-bit identifier */
CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh);
}
if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_32bit)
{
/* 32-bit scale for the filter */
CANx->FS1R |= filter_number_bit_pos;
/* 32-bit identifier or First 32-bit identifier */
CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow);
/* 32-bit mask or Second 32-bit identifier */
CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow);
}
/* Filter Mode */
if (CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdMask)
{
/*Id/Mask mode for the filter*/
CANx->FM1R &= ~(uint32_t)filter_number_bit_pos;
}
else /* CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdList */
{
/*Identifier list mode for the filter*/
CANx->FM1R |= (uint32_t)filter_number_bit_pos;
}
/* Filter FIFO assignment */
if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO0)
{
/* FIFO 0 assignation for the filter */
CANx->FFA1R &= ~(uint32_t)filter_number_bit_pos;
}
if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO1)
{
/* FIFO 1 assignation for the filter */
CANx->FFA1R |= (uint32_t)filter_number_bit_pos;
}
/* Filter activation */
if (CAN_FilterInitStruct->CAN_FilterActivation == ENABLE)
{
CANx->FA1R |= filter_number_bit_pos;
}
/* Leave the initialisation mode for the filter */
CANx->FMR &= ~FMR_FINIT;
}
软件相关部分:
由于CAN1的IO是使用的PB8,PB9,使用的是重映射1,软件需要配置重映射。
软件方面设定CAN的波特率是500k,使用的中断方式接收数据,接收到的帧的ID如果是我们设定的ID那就把收到的数据给打印出来,CAN1发送的帧的ID是0x11,CAN2发送的帧的ID是0x12。
相关代码如下:
u8 CAN1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //使能CAN1时钟
GPIO_PinRemapConfig(GPIO_Remap1_CAN1,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化IO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化IO
//CAN单元设置
CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式
CAN_InitStructure.CAN_ABOM=ENABLE; //软件自动离线管理
CAN_InitStructure.CAN_AWUM=ENABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
CAN_InitStructure.CAN_NART=DISABLE; //禁止报文自动传送
CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
CAN_InitStructure.CAN_Mode= CAN_Mode_Normal; //模式设置: mode:0,普通模式;1,回环模式;
//设置波特率 36M/((8+9+1)*4)=500Kbps
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
CAN_InitStructure.CAN_BS1=CAN_BS1_9tq; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2=CAN_BS2_8tq; //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=4; //分频系数(Fdiv)为brp+1
CAN_Init(CAN1, &CAN_InitStructure); //初始化CAN1
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位宽
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0
CAN_FilterInit(CAN1,&CAN_FilterInitStructure); //滤波器初始化
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //FIFO0消息挂号中断允许.
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 主优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // 次优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
return 0;
}
u8 CAN2_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);//使能CAN2时钟
//CAN2 GPIO配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //带上拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
//CAN单元设置
CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式
CAN_InitStructure.CAN_ABOM=ENABLE; //软件自动离线管理
CAN_InitStructure.CAN_AWUM=ENABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
CAN_InitStructure.CAN_NART=DISABLE; //禁止报文自动传送
CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
CAN_InitStructure.CAN_Mode= CAN_Mode_Normal; //模式设置: mode:0,普通模式;1,回环模式;
//设置波特率 36M/((8+9+1)*4)=500Kbps
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
CAN_InitStructure.CAN_BS1=CAN_BS1_9tq; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2=CAN_BS2_8tq; //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=4; //分频系数(Fdiv)为brp+1
CAN_Init(CAN2, &CAN_InitStructure); //初始化CAN1
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //屏蔽位模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位宽
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0
CAN_FilterInit(CAN2,&CAN_FilterInitStructure); //滤波器初始化
CAN_ITConfig(CAN2,CAN_IT_FMP0,ENABLE); //FIFO0消息挂号中断允许.
NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 主优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 次优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
return 0;
}
//中断服务函数
void CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
int i=0;
CAN_Receive(CAN1, 0, &RxMessage);
printf ("CAN1_RX0_IRQHandler:\r\n");
if(RxMessage.StdId==0x12)
{
printf ("rxbuf:\r\n");
for(i=0;i<8;i++)
printf("%02x ",RxMessage.Data[i]);
}
printf("\r\n");
}
void CAN2_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
int i=0;
CAN_Receive(CAN2, 0, &RxMessage);
printf ("CAN2_RX0_IRQHandler:\r\n");
if(RxMessage.StdId==0x11)
{
printf ("rxbuf:\r\n");
for(i=0;i<8;i++)
printf("%02x ",RxMessage.Data[i]);
}
printf("\r\n");
}
//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//len:数据长度(最大为8)
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
// 其他,失败;
u8 Can1_Send_Msg()
{
u8 mbox;
u16 i=0;
CanTxMsg TxMessage;
TxMessage.StdId=0x11; // 标准标识符
TxMessage.ExtId=0x12; // 设置扩展标示符
TxMessage.IDE=CAN_Id_Standard; // 标准帧
TxMessage.RTR=CAN_RTR_Data; // 数据帧
TxMessage.DLC=8; // 要发送的数据长度
TxMessage.Data[0]=0x01;
TxMessage.Data[1]=0x01;
TxMessage.Data[2]=0x01;
TxMessage.Data[3]=0x01;
TxMessage.Data[4]=0x01;
TxMessage.Data[5]=0x01;
TxMessage.Data[6]=0x01;
TxMessage.Data[7]=0x01;
mbox= CAN_Transmit(CAN1, &TxMessage);
i=0;
while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++; //等待发送结束
if(i>=0XFFF)return 1;
return 0;
}
u8 Can2_Send_Msg()
{
u8 mbox;
u16 i=0;
CanTxMsg TxMessage;
TxMessage.StdId=0x12; // 标准标识符
TxMessage.ExtId=0x12; // 设置扩展标示符
TxMessage.IDE=CAN_Id_Standard; // 标准帧
TxMessage.RTR=CAN_RTR_Data; // 数据帧
TxMessage.DLC=8; // 要发送的数据长度
TxMessage.Data[0]=0x02;
TxMessage.Data[1]=0x02;
TxMessage.Data[2]=0x02;
TxMessage.Data[3]=0x02;
TxMessage.Data[4]=0x02;
TxMessage.Data[5]=0x02;
TxMessage.Data[6]=0x02;
TxMessage.Data[7]=0x02;
mbox= CAN_Transmit(CAN2, &TxMessage);
i=0;
while((CAN_TransmitStatus(CAN2, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++; //等待发送结束
if(i>=0XFFF)return 1;
return 0;
}
int main(void)
{
u8 t=0;
RCC_Config();
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
printf ("AT32F403A 替换SXX32f105 双can通讯测试!!\r\n");
AT32LED_Init();
CAN1_Init();
CAN2_Init();
GetClk();
while(1)
{
t++;
delay_ms(10);
if(t%50==0)
{
LED4=!LED4;//提示系统正在运行
}
if(t%100==0)
{
Can1_Send_Msg();
delay_ms(500);
Can2_Send_Msg();
LED2=!LED2;
}
}
}
测试结果
通过看串口助手的log,程序已经运行起来,收发的数据和我们设定的是一致的:
总结
AT32F403A的CAN2和STM32F105的CAN2是不一样的,不能兼容。必须修改库才能在AT32上使用,主要就是中断号以及滤波器不一样。
本文仅供于学习、测试使用。
有什么问题的可加qq群技术交流。