【STM32L496】HAL库实现HART协议收发数据(AD5700)

HART原理

HART (Highway Addressable Remote Transducer)协议采用基于 Bell202 标准的 FSK频 移键控信号,在低频的 4-20mA模拟信号上叠加幅度为 0.5mA的音频数字信号进行双向数字通讯,数据传输率为1200bps。
HART具有三类命令,其中第一类称为通用命令,这是所有设备都理解、执行的命令;第二类称为普通应用命令,所提供的功能可以在许多现场设备(尽管不是全部)中实现;第三类称为设备专用命令,以便于工作在某些设备中实现特殊功能,这类命令既可以在基金会中开放使用,又可以为开发此命令的公司所独有。
HART位流之前是一个标准UART帧,该帧包含一个起始位、8位数据、一个奇偶校验和一个停止位。
想要知道更多,可以通过下面这些链接了解HART原理。
HART通信协议
讲一讲HART协议
讲一讲HART协议命令格式

AD5700芯片了解

AD5700不仅继承调制和解调功能,而且还内置基准电压源、接收带通滤波器(可根据需要灵活地进行旁路)和缓冲HART输出,能够提供高输出驱动能力且无需外部缓冲。并且AD5700能够发射或接收1.2 kHz和2.2 kHz载波信号。1.2 kHz信号表示数字1(即传号),2.2 kHz信号则表示0(即空号)。
在这里,我用的芯片是AD5700-1,AD5700和AD5700-1有什么区别,在芯片手册中写得很清楚,比较直观的一点就是,AD5700-1支持使能内部振荡器且使能CLKOUT,因为其中有一个低功耗RC振荡器,所以在配置内部时钟时,AD5700-1芯片可以利用这个内部振荡器来配置。
AD5700-1
时钟配置
不过如果使用内部RC振荡器,此时钟输出只能为1.2288 MHz缓冲时钟。

HAL库配置及初始化

AD5700芯片引脚定义在STM32L496芯片引脚的示意图如下,仅供参考。
在本文,CLK_CFG0和CLK_CFG1共同用一个GPIO引脚来控制输出。
(还好评论指出错误,已修改)
AD5700与STM32L4的引脚配置表
在这里先使能RTS引脚,使5700一直在等待上位机有数据发给5700(5700一直在等消息接收)。
GPIO引脚配置
定义usart2为接受与发送HART命令的引脚。
接收发送

时钟配置选项,这里使用内部振荡器,输出1.2288MHz的时钟。
时钟配置选项
针对HART调制解调命令流程,可以作如下片面理解:
1.发送命令0给从机,等待从机回应;
2.收到回应后,需要对回应进行相应的解析(此时会返回厂商代码、设备序列号、处理数据等);
3.利用返回的结果进行长指令通信,然后改命令,对不同命令进行解析,获得自己想要的信息。

部分代码

i.这里的部分代码指的是在main.c文件下配置HART的函数,并不包含HART接收命令后做数据处理的函数。
ii.HART协议的通用命令可以在网上找到。HART通用命令
iii.该工程的AD5700为搭配AD5421使用,如有需要,可浏览本人主页的【AD5421】文章。
HART时钟配置函数

float EnableHartClk(void)
{
	uint32_t cnt = 0;
	float freq = 0;
	TIM3_CH2_Flag = 0;
	TIM3_CH2_Overflow = 0;
	TIM3_CH2_Count[0] = 0;
	TIM3_CH2_Count[1] = 0;
	TIM_RESET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2);
	__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);
	HAL_TIM_Base_Start_IT(&htim3);
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
	
	while(TIM3_CH2_Flag < 2);
	TIM3_CH2_Flag = 0;
	cnt = TIM3_CH2_Overflow*(0xffff+1)+TIM3_CH2_Count[1]-TIM3_CH2_Count[0];
	freq = 50000000.0f/cnt;
	TIM3_CH2_Overflow = 0;
	TIM3_CH2_Count[0] = 0;
	TIM3_CH2_Count[1] = 0;
	
	printf("Hart Clock = %0.4f Hz\n",freq);
	return freq;
}

AD5700初始化函数

void Init_AD5700(void)
{
	//ADC检测	
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);//enable HART_CLK_CFG
//	//时钟检测
//	enableHartClk();
//	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);//Disable_HART_CLK_CFG;
	ad5700Hart(NULL,0,false);
}

控制AD5700的调制与解调

//操作AD5700的HART调制or解调
void ad5700Hart(uint8_t *dat,uint8_t dsize,bool modulate)
{
	if(modulate)//调制
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_RESET);
		delay_ms(10);
		HAL_UART_Transmit(&huart4,dat,dsize,0xFFFF);
	}
	else//解调
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_SET);//enable AD5700_RTS
		delay_ms(10);
		HAL_UART_Receive_IT(&huart4,&HART_RxBit,1);//开启中断,HART_RxBit为全局变量下定义的buf
	}
}

回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == &huart2)//5700
	{
		HART_RxBuffer[HART_RxFlag]=HART_RxBit;
		HART_RxBit=0;
		HART_Timer_Flag=0;
		HAL_TIM_Base_Start_IT(&htim4);
		HART_RxFlag++;
		HAL_UART_Receive_IT(&huart2,&HART_RxBit,1);
	}
}

控制HART的定时器回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim == &htim4)
	{
		HART_Timer_Flag++;
		if(HART_Timer_Flag >= 10)
		{
			HART_RxFlag = 0;
			HART_Timer_Flag = 10;
			HAL_TIM_Base_Stop_IT(&htim4);
		}
	}
	else if(htim == &htim3)
	{
		TIM3_CH2_Overflow++;
	}
}

这里其实还有一个获得主变量PV值的一个函数,和一个控制电流输出PV值的函数。前者是通过ad5421_read函数读失调调整寄存器和增益调整寄存器的值;并判断是否为输出电流模式,是则判断固定电流模式是否为0,不为0则写入该电流值,否则计算相应的电流输出值(调用后者函数,控制AD5421的DAC)。
这部分内容还在整理… …

遇到的问题

在网上直接搜HART,可以搜到不少与其相关的概念知识(比如工作原理、消息结构[下图]这种),但是却很少能找到和hart相关的代码,刚开始接触HART的时候,配置完引脚之后根本不知道要从哪里下手写程序。
网上搜到的规范

并且AD5700芯片也没接触过… …看它手册里写得头头是道的,但也仅限于按照原理图配引脚了,最后还是得找示例代码来抄,代码量不小,功能函数较多,前几天看的时候头挺晕的,后面跟着debug跑的时候也大概知道了它的工作流程是怎么样的了。
并且在一开始写(chao)功能代码的时候,控制调制解调的引脚不知道为什么被我配成了外部中断… …应该是输出才对… …最后还是靠同事来看才发现是配置开始就配错了,无语(ˉ▽ˉ川)…
GPIO_Output

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 23
    评论
#include "use.h" #include "Ver.H" #include #include #include #include "include.h" /******************************************************************* 1、菜单中这几个参数项需要读出和修改: P1中的:L,H,E,dr,P P2中的:Ed,SF,bo 一共7个参数项; ---这7个参数项不知道用什么命令来进行读写? 请你帮助考虑一下。 2、HART命令中,有如下命令应该要用到: ⑴ 0#命令---读标识码 (好像是个广播命令) ⑵ 3#命令---读主变量电流(测量值) ⑶ 6#命令---置随选地址(确定工作模式) ⑷ 15#命令---读主变量输出信息(上下限值) ⑸ 40#命令---进入/退出电流模式 ⑹ 41#命令---执行设备自检 ⑺ 42#命令---执行设备复位 ******************************************************************/ //前面的4个地址是固定的,后面一个是可以改的!用MP1.ADR 代替了! //#define adr0 0x02 //#define adr1 0x23 //#define adr2 0x34 //#define adr3 0x45 //#define MAX_0xff 5 //前导符的个数! //#define HART_VER 5 // 版本 //---------------------------------------------------------------------------------- //static unsigned char fHART_LONG_ADR=0; //=0 短地址标至;=1 是长地址! //static unsigned char cnt_0xff=MAX_0xff; //主机发送0XFF的个数,从机回复添加相同的个数 ! //************************************************************************** extern unsigned char cnt_0xff; //主机发送0XFF的个数,从机回复添加相同的个数 ! extern unsigned char fHART_LONG_ADR; //=0 短地址标至;=1 是长地址! //--------------------------------------------------------------------------------------------- unsigned char HART_Get_FF(unsigned char *p){ memset(p,0xff,cnt_0xff); return cnt_0xff;
STM32F407 HAL库是一种高级的嵌入式软件开发工具,旨在简化STM32F407微控制器的编程过程。针对不定长数据的中断接收,我们可以借助HAL库的中断功能来实现。以下是具体步骤: 1. 配置USART串口接收参数:在HAL库中,可以通过函数HAL_UART_Init()来配置USART接口的参数,例如波特率、数据位数、奇偶校验位、停止位等。 2. 启用USART接口中断:在配置完USART接口参数后,我们需要使能USART接收数据中断。可以通过函数HAL_UART_Receive_IT()来实现,该函数的第二个参数即为缓冲区大小。 3. 编写USART接收中断处理函数:接下来,我们需要编写USART串口接收中断处理函数。该函数名称与HAL库函数名一一对应,例如我们可以写一个函数HAL_UART_RxCpltCallback(),用于在接收完成时自动调用该函数。 4. 读取接收到的数据:在中断处理函数中,我们需要读取接收到的数据。通过HAL库中的函数HAL_UART_Receive_IT(),可以从USART接口接收数据,并将其存储在缓冲区中。我们可以通过读取缓冲区中的数据实现不定长数据的接收。 5. 停止数据接收:在读取完所有数据后,我们需要停止数据接收。可以通过HAL库中的函数HAL_UART_AbortReceive_IT()来实现。 通过以上步骤,我们就可以使用STM32F407 HAL库实现不定长数据的中断接收了。该方法具有高效、稳定的特点,是一种比较流行的实现方式。
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值