ADS805E的驱动——STM32F407&cubeMX

ADS805E是一个ADC,12位,最高采样率为20MHz,估计这个采样率才是它代替单片机采样的优势所在。

详细的信息可以参考数据手册,我们拿到外设之后一般关心下面这几个参数:供电引脚、供电电压、输入信号范围、输出信号范围,对于程控模块,我们还关心它的控制寄存器地址、数据寄存器地址、通信协议等等。

这个图是引脚定义,但是在读数据手册的时候发现还有一个芯片,bbref0425,搜出来是一个参考源,2.5V

看起来好麻烦,这些引脚也挺复杂的,但是这些我们都不用关心,因为都在板子上,印出来的接上,没有引出来的我们就不管。

之前驱动的板子一般都会有控制寄存器和数据寄存器,从哪里写数据读数据都会给出,但是我扫了一遍数据手册只发现了一个时序图,看来这个芯片的驱动比想象中的简单。

看出基本时序:在时钟的上升沿开始采样,在下降沿可以读数据。就这么简单。

那我们只需要验证一下时钟信号的要求和控制引脚的电平就好了。

根据上面引脚图,OE是输出使能,差不多算是片选的意思,当我们拉低的时候芯片正常运行,当我们拉高的时候就是高阻态,这有利于我们使用同一组数据线进行扩展(用到一点点数电的知识,总线上的设备分时公用一根数据线,不使用时是高阻态)

还有一个OVR引脚是啥意思呢,翻译一下是超量程指示器,当输入模拟电压低于参考低电平或高于参考高电平时这个输出为1,正常工作就是0

好了,现在看供电,板子上有两个电源,AVDD和DVDD,通过板子的电路图就可以看到,AVDD直接接到了VS(5V)和SEL引脚,那肯定是要供5V的,但是SEL是干啥的?一个选择引脚,我们看看手册的这张图:

不难发现当我们把SEL接到VS时,模拟量输入范围是1-5V(先这么猜一下)

还有一个DVDD引脚接到了芯片的VDRV引脚,我翻译了一下简介:

ADS805的数字输出设计兼容高速TTL和CMOS逻辑家族。数字输出的驱动级通过一个单独的电源引脚VDRV供电,VDRV没有连接到模拟电源引脚。通过调整VDRV上的电压,数字输出电平将分别变化。因此,有可能在+5V模拟电源上运行ADS805,同时将数字输出接口到3V逻辑,VDRV引脚连接到+3V数字电源。

这段不愧是翻译出来的,晦涩难懂。我简单给大家翻一下:就是说这个要用数字电源供电,3-3.3V最好,这就是数字信号输出时的高电平驱动电源。

还有下一段我也翻译了,大概意思就是说通过这个引脚的电流不要太大,也就是数字输出引脚上的负载电容不要太大,否则可能影响ADC的精度。

Ok,到此为止我们就弄清了所有引脚的功能。那就简单写个驱动程序做一下试试。

本质上是读数据,利用时钟的中断频率来表示采样频率,然后将引脚拉高拉低模拟出CLK信号,然后通过12个引脚来读数据量。

具体连接就是板子上最右边那一排,从上到下依次连接1-12数据,然后PD0连接CLK,PD3连接OE,PD5连接OVR,AVDD供电5V,DVDD供电3.3V,为了防止超限,我供的4.9和3.2,信号输入GND和VIN,所有地都连在一起

简单介绍一下工程的移植过程:

在cubeMX中只需要启用TIM2(顺便勾上全局中断),启用一个GPIO(随便哪个都可以),启用USART1作为UART通信。

把时钟配置一下,将系统时钟配到168M就可以

生成工程选择单独生成.c和.h文件

下面是.h文件

#ifndef ADS805E_H
#define ADS805E_H

#include "tim.h"
#include "gpio.h"

/*
 *	注意:本库函数用于驱动ADS805E芯片的ADC模块
 *	在使用之前需要使能一个定时器2,剩下的配置直接在本库函数中完成
 *	本次驱动外设的思路是利用定时器产生一个中断,中断频率就是采样频率
 *	该外设引脚较多,请根据注释进行连接
 *	连接:参考下面的定义
 */

#define	D1_GPIO		GPIOC
#define	D1_PIN		GPIO_PIN_6
#define	D2_GPIO		GPIOD
#define	D2_PIN		GPIO_PIN_6
#define	D3_GPIO		GPIOG
#define	D3_PIN		GPIO_PIN_15
#define	D4_GPIO		GPIOC
#define	D4_PIN		GPIO_PIN_11
#define	D5_GPIO		GPIOC
#define	D5_PIN		GPIO_PIN_12
#define	D6_GPIO		GPIOC
#define	D6_PIN		GPIO_PIN_8
#define	D7_GPIO		GPIOG
#define	D7_PIN		GPIO_PIN_6
#define	D8_GPIO		GPIOG
#define	D8_PIN		GPIO_PIN_8
#define	D9_GPIO		GPIOA
#define	D9_PIN		GPIO_PIN_12
#define	D10_GPIO	GPIOB
#define	D10_PIN		GPIO_PIN_6
#define	D11_GPIO	GPIOB
#define	D11_PIN		GPIO_PIN_3
#define	D12_GPIO	GPIOB
#define	D12_PIN		GPIO_PIN_10
#define	CLK_GPIO	GPIOD
#define	CLK_PIN		GPIO_PIN_2
#define	OE_GPIO		GPIOD
#define	OE_PIN		GPIO_PIN_3
#define	OVR_GPIO	GPIOD
#define	OVR_PIN		GPIO_PIN_7

//定时器初始化函数
void ADS805E_init(void);	//只需要这一句就可以
void ADS805E_GPIO_init(void);
void ADS805E_TIM_Init(void);
//读取数值的函数
uint16_t ADS805(void);

#endif

然后是.c文件

#include "ADS805E.h"

uint16_t flag = 0;

void ADS805E_GPIO_init(void)
{
	 GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_3, GPIO_PIN_RESET);

  /*Configure GPIO pins : PB10 PB3 PB6 */
  GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_3|GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PG6 PG8 PG15 */
  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_8|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /*Configure GPIO pins : PC6 PC8 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_8|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA12 */
  GPIO_InitStruct.Pin = GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PD2 PD3 */
  GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /*Configure GPIO pins : PD5 PD6 */
  GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_6;	
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}

void ADS805E_TIM_Init(void)
{
	TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 84-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 2-1;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
	
	//以下三行是配置定时器中断
	__HAL_RCC_TIM2_CLK_ENABLE();
	HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
	HAL_NVIC_EnableIRQ(TIM2_IRQn);
  
	//启用中断
	HAL_TIM_Base_Start_IT(&htim2);		
}

void ADS805E_init(void)
{
	ADS805E_GPIO_init();
	ADS805E_TIM_Init();
}

uint16_t ADS805(void)
{
	HAL_GPIO_WritePin(OE_GPIO, OE_PIN, GPIO_PIN_RESET);
	uint16_t adc_value= 0;
	if(flag == 0)
	{
		flag = 1;
		HAL_GPIO_WritePin(CLK_GPIO, CLK_PIN, GPIO_PIN_RESET);
		adc_value |= HAL_GPIO_ReadPin(D1_GPIO,D1_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D2_GPIO,D2_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D3_GPIO,D3_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D4_GPIO,D4_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D5_GPIO,D5_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D6_GPIO,D6_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D7_GPIO,D7_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D8_GPIO,D8_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D9_GPIO,D9_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D10_GPIO,D10_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D11_GPIO,D11_PIN);
		adc_value = adc_value << 1;
		adc_value |= HAL_GPIO_ReadPin(D12_GPIO,D12_PIN);
	}
	else
	{
		flag = 0;
		HAL_GPIO_WritePin(CLK_GPIO, CLK_PIN, GPIO_PIN_SET);
	}
	return adc_value;
}

//下面三个定义需要,放在主函数中

/*
extern uint16_t flag;
uint16_t adc = 0;
uint16_t adc_buff[480] = {0};
*/

//下面部分的代码为中断回调函数,放在主函数中即可

/*
int cnt_tim = 0;
//定时器1的中断,测频的主体
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
   if(htim->Instance==TIM2)	//判断是不是定时器1引发的中断
	 {
		 if(flag == 0)
		 {
			 adc = ADS805();
			 adc_buff[cnt_tim] = adc;
			 cnt_tim++;
			 cnt_tim %= 480;		//一定不要忘了这一句哈,单片机的程序数组访问超限会造成未知错误!!!!
		 }
		 else ADS805();
		 
	 }
}
*/

//主函数中可以判断数据是否正常,如果超出量程就会输出error,例如:

/*
while(1)
{
		if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_5) == GPIO_PIN_RESET)	printf("OK!");
		if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_5) == GPIO_PIN_SET)	printf("error!");
		HAL_Delay(500);
}
*/

然后把Drive中的ADS805E文件夹拖过来,连接.h库的位置,然后按照.c文件下面的三个指示修改main函数

这篇只是作为一个记录存在,如果大家需要工程可以留下邮箱,后面我是将它和LCD集成在了一起,可能还需要用屏幕显示波形,也可以改一下用串口打印。

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值