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集成在了一起,可能还需要用屏幕显示波形,也可以改一下用串口打印。