title: DAY11-CAN总线和ADC
categories: STM32
abbrlink: 221cbc9c
date: 2022-07-28 23:46:42
(3)控制段
r0,r1为保留位,默认是显性电平 DLC由4位组成,表示数据段的长度(0~8)
(4)数据段
长度0~8字节,高位先出
(5)CRC段
CRC错误校验,由15位CRC校验码和1位界定符组成,校验出错反馈错误信息,利用错误帧请求重发,重发次数可以通过软件设置。
(6)ACK段
由一位ACK槽和一位ACK界定符组成,发送方的ACK槽是隐性电平,接收方确认收到正确的数据后以显性电平作为应答。
(7)帧结束
7位隐性电平
4.CAN的位时序
CAN传输1位由4段组成:同步段,传播段,相位缓冲段1,相位缓冲段2。1位结束后会使用再同步补偿宽度(SJW)进行再补偿,这样设计的原因是让发送方和接收方的时序保持统一(没有时钟线)
(1)同步段(SS)
同步段用于实现时序的调整,完成显性电平/隐性电平的转换,也就是准备该位要发送的电平
(2)传播时间段(PTS)
用于吸收网络上的物理延迟,物理延迟包括发送的延迟,接收的延迟和信号传播的延迟。
(3)相位缓冲段(PBS)
对于电平转换未被包含的部分进行补偿,同时和SJW一起补偿各单位的时钟误差,读取电平在该段完成。
(4)再同步补偿宽度(SJW)
补偿前面同步的误差
注意:接收方的采样一定在PBS1和PBS2之间,由于PTS误差的变动,PBS的补偿也会随着误差的变化而变化,实现1位传输时间的固定,SJW对PBS的补偿进行二次补偿。
1位时间 = 8~25Tq
SS = 1Tq
PTS = 1~8Tq
PBS = 2~8Tq
SJW = 1~4Tq
5.stm32f4的CAN控制器
stm32芯片带有bxCAN控制器,支持CAN协议的2.0A和2.0B,最快速度支持1Mbps,能够自动发送CAN报文,支持标准帧和扩展数据帧,控制器带有三个发送邮箱存储报文,还有两个FIFO,支持ID过滤,可配置自动重发。
(1)工作模式
初始化模式:初始化CAN控制器
正常模式:正常发送和接收数据
睡眠模式:低功耗
(2)测试模式
静默模式:停止对外发送报文
环回模式:报文不发送到总线,直接发给自己
环回和静默组合模式
调试模式
(3)通信速率
波特率 = 42M/分频系数/(tbs1+tbs2+sjw)
(4)接收中断
FMPx表示收到消息
6.原理图
连接到了CPU的PD0 PD1,具有CAN的复用功能
7.CAN总线通信的库函数实现
添加CAN总线通信的库函数源码
(1)开启GPIOD和CAN1的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
(2)配置GPIO为CAN复用功能
GPIO_Init(...);
GPIO_PinAFConfig(...);
(3)初始化CAN1
uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct);
参数:
CANx - 哪路CAN
CAN_InitStruct - CAN初始化结构
typedef struct
{
uint16_t CAN_Prescaler; /*!< 总线时钟的分频系数 1 to 1024. */
uint8_t CAN_Mode; /*!< 工作模式 @ref CAN_operating_mode */
uint8_t CAN_SJW; /*!< SJW极限值 @ref CAN_synchronisation_jump_width */
uint8_t CAN_BS1; /*!< 相位缓冲段1长度 @ref CAN_time_quantum_in_bit_segment_1 */
uint8_t CAN_BS2; /*!< 相位缓冲段2长度 @ref CAN_time_quantum_in_bit_segment_2 */
FunctionalState CAN_TTCM; /*!< 时间触发使能 ENABLE or DISABLE. */
FunctionalState CAN_ABOM; /*!< 自动离线使能 ENABLE or DISABLE. */
FunctionalState CAN_AWUM; /*!< 自动唤醒使能 ENABLE or DISABLE. */
FunctionalState CAN_NART; /*!< 自动重发使能 ENABLE or DISABLE. */
FunctionalState CAN_RFLM; /*!< 接收FIFO锁定使能 ENABLE or DISABLE. */
FunctionalState CAN_TXFP; /*!< 发送FIFO优先级使能 ENABLE or DISABLE. */
} CAN_InitTypeDef;
(3)初始化过滤器
void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct);
//参数就是过滤器初始化结构
typedef struct
{
uint16_t CAN_FilterIdHigh; /*!< 过滤器ID寄存器的高16位 0x0000 and 0xFFFF */
uint16_t CAN_FilterIdLow; /*!< 过滤器ID寄存器的低16位 0x0000 and 0xFFFF */
uint16_t CAN_FilterMaskIdHigh; /*!< 过滤器屏蔽寄存器的高16位 0x0000 and 0xFFFF */
uint16_t CAN_FilterMaskIdLow; /*!< 过滤器屏蔽寄存器的低16位 0x0000 and 0xFFFF */
uint16_t CAN_FilterFIFOAssignment; /*!< 接收FIFO的选择 @ref CAN_filter_FIFO */
uint8_t CAN_FilterNumber; /*!< 过滤器编号 0 to 13. */
uint8_t CAN_FilterMode; /*!< 过滤器模式 @ref CAN_filter_mode */
uint8_t CAN_FilterScale; /*!< 过滤器长度 @ref CAN_filter_scale */
FunctionalState CAN_FilterActivation; /*!< 过滤器使能 ENABLE or DISABLE. */
} CAN_FilterInitTypeDef;
(5)配置发送/接收的结构体
//发送数据结构体
typedef struct
{
uint32_t StdId; /*!< 标准帧ID 0 to 0x7FF. */
uint32_t ExtId; /*!< 扩展帧ID 0 to 0x1FFFFFFF. */
uint8_t IDE; /*!< IDE标志 标准帧/扩展帧 @ref CAN_identifier_type */
uint8_t RTR; /*!< RTR标志 数据帧/遥控帧 @ref CAN_remote_transmission_request */
uint8_t DLC; /*!< 数据段长度 0 to 8 */
uint8_t Data[8]; /*!< 数据内容 0 to 0xFF. */
} CanTxMsg;
//接收数据结构体
typedef struct
{
uint32_t StdId; /*!< 标准帧ID 0 to 0x7FF. */
uint32_t ExtId; /*!< 扩展帧ID 0 to 0x1FFFFFFF. */
uint8_t IDE; /*!< IDE标志 标准帧/扩展帧 @ref CAN_identifier_type */
uint8_t RTR; /*!< RTR标志 数据帧/遥控帧 @ref CAN_remote_transmission_request */
uint8_t DLC; /*!< 数据段长度 0 to 8 */
uint8_t Data[8]; /*!< 数据内容 0 to 0xFF. */
uint8_t FMI; /*!< 过滤器放入的内容 0 to 0xFF */
} CanRxMsg;
(6)初始化CAN的接收中断
NVIC_Init(...);
CAN_ITConfig(...);
(7)发送和接收数据的接口
接收:
void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage);
发送:
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage);
uint8_t CAN_TransmitStatus(CAN_TypeDef* CANx, uint8_t TransmitMailbox);
8.上位机使用
打开上位机软件
(1)串口设置
打开后会读到当前模块的设置
(2)将CAN模块设置为环回模式,波特率500Kbps
(3)测试模块的发送和接收
9.模块和开发板的连接
练习:
将两块开发板的CAN接口连接,测试互相发送和接收
如果没有两块开发板使用环回模式自己发给自己
10.CAN的过滤器设置
stm32的CAN过滤器有两种模式:列表模式和掩码模式
(1)列表模式
列表模式表示只接收符合给定ID的帧,一共有2个32位的寄存器,分为16位模式和32位模式。
16位列表模式一个ID占16位,一共可以给4个ID,通常用于标准帧,标准帧的ID放入16位中的高11位。扩展帧只能存ID的15~17于低三位,另外两位存IDE位和RTR位,分别表示扩展帧(1)/标准帧(0),数据帧(0)/遥控帧(1)。
32位列表模式一个ID占32位,一共可以给2个ID,通常用于扩展帧,扩展帧的ID是29位,放入寄存器的高29位,低位放IDE,RTR和0
(2)掩码模式
掩码模式只接收符合掩码要求的帧,一共有2个32位的寄存器,分为16位模式和32位模式。
第一个寄存器给ID的值,第二个寄存器对一个寄存器进行掩码操作,只有第一个寄存器中对应第二个寄存器中为1的位才需要匹配。
三十.ADC
1.概念
ADC,指的是Analog-to-Digtal Converter(模数转换)。我们把连续变化的信号叫模拟信号,离散的非连续的信号叫数字信号,现实生活中所有的信号属于模拟信号,比如声音,电压,压强,温度.......,但是计算机只能存储和处理数字信号。ADC实现的就是这种将模拟信号转换成数字信号的功能,DAC将数字信号转换成模拟信号。
2.ADC的转换过程
采样 ======> 量化 =====> 编码
3.ADC类型
ADC有积分型和逐次逼近型的区分,积分型电路简单,成本低,但是转换事件比较长。逐次逼近型成本相对高,转换速度相对快。
4.stm32f4的内部ADC
注:P10跳线为ADC提供参考正电压,必须连上ADC才能工作,测量范围:0 ~ 3.3V
ADC测量电路:
滑动变阻器的分压引脚连接到了PA5,PA5具有ADC12的通道5的复用功能
5.ADC的库函数编程实现
添加ADC的库函数源码到工程中
(1)开启GPIOA和ADC1时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
(2)将GPIO配置为模拟功能
GPIO_Init
(3)复位ADC
ADC_DeInit(...);
(4)初始化ADC的分频系数(配置CCR寄存器,通用配置)
void ADC_CommonInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct);
//参数就是初始化结构体
typedef struct
{
uint32_t ADC_Mode; /*!< 模式选择 多重/独立 @ref ADC_Common_mode */
uint32_t ADC_Prescaler; /*!< 分频系数 4分频 @ref ADC_Prescaler */
uint32_t ADC_DMAAccessMode; /*!< DMA模式选择 @ref ADC_Direct_memory_access_mode_for_multi_mode */
uint32_t ADC_TwoSamplingDelay; /*!< 2次采样时间间隔 5时钟周期 @ref ADC_delay_between_2_sampling_phases */
}ADC_CommonInitTypeDef;
(5)初始化ADC1,设置工作模式,规则序列(专用配置)
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
参数:
ADCx - 哪个ADC
ADC_InitStruct - ADC初始化结构
typedef struct
{
uint32_t ADC_Resolution; /*!< 分辨率 12位 @ref ADC_resolution */
FunctionalState ADC_ScanConvMode; /*!< 扫描使能 DISABLE */
FunctionalState ADC_ContinuousConvMode; /*!< 连续转换使能 DISABLE. */
uint32_t ADC_ExternalTrigConvEdge; /*!< 外部触发信号选择 @ref ADC_external_trigger_edge_for_regular_channels_conversion */
uint32_t ADC_ExternalTrigConv; /*!< 外部触发选择 @ref ADC_extrenal_trigger_sources_for_regular_channels_conversion */
uint32_t ADC_DataAlign; /*!< 数据对齐选择 @ref ADC_data_align */
uint8_t ADC_NbrOfConversion; /*!< 规则序列长度 1 */
}ADC_InitTypeDef;
(6)使能ADC
ADC_Cmd(...);
(7)配置通道参数(转换ADC哪个通道,采样周期)
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
参数:
ADCx - 哪个ADC
ADC_Channel - 哪个通道
Rank - 规则组的编号
ADC_SampleTime - 采样周期
(8)使用软件操作启动转换
void ADC_SoftwareStartConv(ADC_TypeDef* ADCx);
(9)等待转换完成
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)!=SET);
(10)获取转换结果
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
6.光敏电阻
光敏电阻的阻值会随着光照强度的变化而变化
作业:
1.通过CAN命令控制LED的亮灭