发新帖我要提问
12
返回列表
打印
[STM32F4]

STM32F4外设配置速查

[复制链接]
楼主: 等你下课
手机看帖
扫描二维码
随时随地手机跟帖
21
等你下课|  楼主 | 2024-3-31 21:42 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
CAN接收流程
FIFO为空
收到有效报文(被正确接收(直到EOF都未出现错误)且通过标识符过滤的报文)
挂号1,存入FIFO的一个邮箱(此步骤由硬件完成)
收到有效报文
挂号2
收到有效报文
挂号3
收到有效报文
溢出,可设置是否锁定,锁定后新数据将被丢弃,不锁定则新数据会替代老数据
通过读取CAN_RFxR的FMP寄存器获取FIFO中当前存储的数据条数,只要不为0则可以读取报文\

使用特权

评论回复
22
等你下课|  楼主 | 2024-3-31 21:42 | 只看该作者
STM32 CAN位时序

应用
初始化流程

配置引脚复用
使能CAN控制器时钟
设置CAN工作模式和波特率
设置过滤器
CAN自动开始工作

使用特权

评论回复
23
等你下课|  楼主 | 2024-3-31 21:42 | 只看该作者
can.c
#include "can.h"
#include <stdio.h>
#include "usart.h"

//CAN1初始化
//使用PA11、PA12引脚输入输出
/***********************************************
        Tsjw:重新同步跳跃时间单元,范围1Tq-4Tq CAN_BS1_1tq-CAN_BS1_16tq
        Tbs2:时间段2的时间单元,范围1Tq-8Tq CAN_BS2_1tq-CAN_BS2_8tq
        Tbs1:时间段1的时间单元,范围1Tq-16Tq
        brp:波特率分频器,范围1-1024       
        计算公式:1个时间单元Tq=(brp)*Tpclk1
        波特率=Fpclk1/(brp*(tbs1+1+tbs2+1+1))
        mode:CAN_Mode_Normal为普通模式,CAN_Mode_LoopBack为回环模式
       
        Fpclk1时钟在初始化时设置为36MHz,
        如果设置sjw=1,bs2=8,bs1=9,brp=4,回环模式,则波特率为36M/((8+9+1)*4)=500Kbps
       
        返回0则正常初始化,返回其他则初始化失败
************************************************/
u8 CAN1_Mode_init(u8 Tsjw,u8 Tbs2,u8 Tbs1,u16 brp,u8 mode)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        CAN_InitTypeDef CAN_InitStruct;
        CAN_FilterInitTypeDef CAN_FilterInitStruct;
       
        //如果使能FIFO消息挂号中断则开启
        #if CAN1_RX0_INT_ENABLE
                NVIC_InitTypeDef NVIC_InitStructure;
       
                CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//使能FIFO消息挂号中断
                NVIC_InitStructure.NVIC_IRQChannel=CAN1_RX0_IRQn;
                NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级为1
                NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//子优先级为0
                NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能FIFO消息挂号中断
        #endif

        //1. 使能GPIO和CAN控制器时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
       
        //2. 初始化PA11、PA12
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//引脚复用
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11|GPIO_Pin_12;//PA11、PA12
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//内部上拉
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//100Mhz
        //应用设置
        GPIO_Init(GPIOA,&GPIO_InitStructure);
       
        //2. 设置引脚复用映射
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1);//PA11复用为CAN1
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1);//PA12复用为CAN1
       
        //3. 设置CAN控制器
                //软件管理设定
        CAN_InitStruct.CAN_TTCM=DISABLE;//非时间触发 通信模式
        CAN_InitStruct.CAN_ABOM=DISABLE;//软件自动离线管理
        CAN_InitStruct.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒
                //报文相关设定
        CAN_InitStruct.CAN_NART=ENABLE;//禁止报文自动传送
        CAN_InitStruct.CAN_RFLM=DISABLE;//报文不锁定,新报文将覆盖堆积旧报文
        CAN_InitStruct.CAN_TXFP=DISABLE;//优先级由报文标识符决定
                //参数设置
        CAN_InitStruct.CAN_Mode=mode;//模式设置
        CAN_InitStruct.CAN_SJW=Tsjw;//同步跳跃宽度设置
        CAN_InitStruct.CAN_BS1=Tbs1;//Tbs1 设置为CAN_BS1_1tq-CAN_BS1_16tq
        CAN_InitStruct.CAN_BS2=Tbs2;//Tbs2 设置为CAN_BS2_1tq-CAN_BS2_8tq
        CAN_InitStruct.CAN_Prescaler=brp;//分频系数=brp+1
        //应用设置
        CAN_Init(CAN1,&CAN_InitStruct);
       
        //4. 设置标识符过滤器
                //基础设置
        CAN_FilterInitStruct.CAN_FilterNumber=0;//使用过滤器0
        CAN_FilterInitStruct.CAN_FilterMode=CAN_FilterMode_IdMask;//使用标识符屏蔽模式
        CAN_FilterInitStruct.CAN_FilterScale=CAN_FilterScale_32bit;//使用32位寄存器模式
                //32位ID设置
        CAN_FilterInitStruct.CAN_FilterIdHigh=0x0000;
        CAN_FilterInitStruct.CAN_FilterIdLow=0x0000;
                //32位掩码设置
        CAN_FilterInitStruct.CAN_FilterMaskIdHigh=0x0000;
        CAN_FilterInitStruct.CAN_FilterMaskIdLow=0x0000;
                //应用过滤器和FIFO设置
        CAN_FilterInitStruct.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//使用FIFO0
        CAN_FilterInitStruct.CAN_FilterActivation=ENABLE;//激活标识符过滤器0
        //应用设置
        CAN_FilterInit(&CAN_FilterInitStruct);
       
        return 0;//完成初始化
}

//如果使能FIFO消息挂号中断则开启,负责接收剩余信息
#if CAN1_RX0_INT_ENABLE
        void CAN1_RX0_IRQHandler(void)
        {
                CanRxMsg CAN_rx_massage;
                int CAN_rx_counter=0;
               
                CAN_Receive(CAN1,0,&CAN_rx_massage);
                for(CAN_rx_counter=0;CAN_rx_counter<8;CAN_rx_counter++)
                        printf("rxbuf[%d]:%d\r\n",CAN_rx_counter,CAN_rx_massage.Data[CAN_rx_counter]);
        }
#endif

//CAN发送数据
//固定格式:ID=0x12,标准帧,数据帧
//msg为数据指针,最大8个字节
//len为数据长度        0-8
//返回0表示成功,返回1表示失败
u8 CAN1_tx_msg(u8* msg,u8 len)
{
        u8 mbox;
        u16 i=0;
        CanTxMsg CAN_tx_massage;
       
        CAN_tx_massage.StdId=0x12;//标准标识符为0
        CAN_tx_massage.ExtId=0x12;//设置29位扩展标识符
        CAN_tx_massage.IDE=0;//使用扩展标识符
        CAN_tx_massage.RTR=0;//消息类型:数据帧,1帧8位
        CAN_tx_massage.DLC=len;//发送2帧消息
       
        for(i=0;i<len;i++)
                CAN_tx_massage.Data[i]=msg[i];//发送信息
       
        mbox=CAN_Transmit(CAN1,&CAN_tx_massage);
       
        i=0;
       
        while((CAN_TransmitStatus(CAN1,mbox)==CAN_TxStatus_Failed)&&(i<0xFFF))
                i++;
        if(i>=0xfff)
                return 1;
        return 0;
}

//CAN接收数据
//buf为数据缓存区
//返回0表示无数据被接收到,若接收到数据则返回接收的数据长度
u8 CAN1_rx_msg(u8* buf)
{
        u32 i;
        CanRxMsg CAN_rx_massage;
       
        if(CAN_MessagePending(CAN1,CAN_FIFO0)==0)
                return 0;
       
        CAN_Receive(CAN1,CAN_FIFO0,&CAN_rx_massage);//读取数据
        for(i=0;i<CAN_rx_massage.DLC;i++)
                buf[i]=CAN_rx_massage.Data[i];
       
        return CAN_rx_massage.DLC;//返回接收到的数据长度
}


使用特权

评论回复
24
等你下课|  楼主 | 2024-3-31 21:42 | 只看该作者
can.h
#ifndef __CAN_H
        #define __CAN_H
        #include "sys.h"
       
        u8 CAN1_mode_init(u8 Tsjw,u8 Tbs2,u8 Tbs1,u16 brp,u8 mode);//CAN1初始化函数
        u8 CAN1_tx_msg(u8* msg,u8 len);//CAN发送数据
        u8 CAN1_rx_msg(u8* buf);//CAN接收数据

#endif

使用特权

评论回复
25
等你下课|  楼主 | 2024-3-31 21:42 | 只看该作者
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "dac.h"
#include "dht11.h"
#include "dma.h"
#include "stmflash.h"
#include "can.h"

int main(void)
{
        u8 key,res,i=0,t=0,cnt=0;
        u8 CAN_buf[8];
        u8 mode=1;//CAN工作模式:1为环回模式,0为普通模式
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组2
       
        delay_init(168);
        uart_init(115200);//串口波特率115200
        LED_init();
        LCD_init();
        KEY_init();
        CAN1_mode_init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack);//初始化为环回模式,波特率500kbps
       
        while(1)
        {
                key=KEY_scan(0);
                if(key==KEY0_PRES)
                {
                        for(i=0;i<8;i++)
                        {
                                CAN_buf[i]=cnt+1;
                                if(i<4)
                                        LCD_ShowxNum(30+i*32,210,CAN_buf[i],3,16,0x80);//显示数据
                                else
                                        LCD_ShowxNum(30+(i-4)*32,230,CAN_buf[i],3,16,0x80);
                        }
                       
                        res=CAN1_tx_msg(CAN_buf,8);//发送8个字节
                       
                        if(res)
                                LCD_ShowString(30+80,190,200,16,16,"Failed");//发送失败
                        else
                                LCD_ShowString(30+80,190,200,16,16,"OK    ");//发送成功
                }
                else if(KEY_init==WKUP_PRES)
                {
                        mode=!mode;
                        CAN1_mode_init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,mode);//初始化为普通模式,波特率500kbps
                       
                        POINT_COLOR=RED;
                       
                        if(mode==0)//普通模式,使用两套开发板通信
                        {
                                LCD_ShowString(30,130,200,16,16,"Normal Mode");
                        }
                        else//环回模式
                        {
                                LCD_ShowString(30,130,200,16,16,"LoopBack Mode");
                        }
                }
               
                key=CAN1_rx_msg();
               
                if(key)
                {
                        LCD_Fill(30,270,160,310,WHITE);
                        for(i=0;i<key;i++)
                        {
                                if(i<4)
                                        LCD_ShowxNum(30+i*32,270,CAN_buf[i],3,16,0x80);//显示数据
                                else
                                        LCD_ShowxNum(30+(i-4)*32,290,CAN_buf[i],3,16,0x80);
                        }
                }
               
                t++;
                delay_ms(10);
               
                if(t==20)
                {
                        LED0=!LED0;
                        t=0;
                        cnt++;
                        LCD_ShowxNum(30+48,170,cnt,3,16,0x80);
                }
        }
}

使用特权

评论回复
26
中国龙芯CDX| | 2024-3-31 21:46 | 只看该作者
CAN是ISO国际标准化的差分串行通信协议,稳定性好

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则