进阶ADC采集
- 1.进阶知识补充
- 2.DMA方式
-
-
- 2.1配置
- 2.2实现
-
- 3.外接高精度ADC(MCP3421)& iic驱动库
-
-
- 3.1 MCP3421 原理图:
- 3.2 MCP3421驱动库:
-
-
- MCP3421.h
- MCP3421.c
-
- 3.3 iic驱动库【模拟iic】:
-
-
- port_iic.h
- port_iic.c
- port_delay.h
- port_delay.h
-
- 3.4 实现:
-
- 4.基础滤波【DMA方式时使用】:
- 5.实训:温度传感器ADC采集:
-
-
- 5.1 way1:DMA
- 5.2 way2:外部18位ADC
-
出门右转上一个album入门HAL库开发 :
链接: 基础HAL库ADC采集(上).
链接: 基础HAL库ADC采集(中).
链接: 基础HAL库ADC采集(下)【转载】.
1.进阶知识补充
STM32的内置ADC:
重要概念:
了解:
2.DMA方式
2.1配置
2.2实现
1.定义一个全局数组给到DMA来存储ADC多路数据:
uint32_t ADC1_Value_DMA[4];
2.start DMA传输:
- 在mian里while(1)外【使能连续模式】
- 在mian里while(1)里【未使能连续模式】
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC1_Value_DMA, 4);//这里的最后一次参数4是代表有4路
还需要把DMA的中断注释掉,否则会一直进中断
这里DMA中断其实没有用,但CubeMx默认给Enable
3.main里加入校准函数 :
HAL_ADCEx_Calibration_Start(&hadc,0xffffffff);//后面的参数似乎没有用
3.外接高精度ADC(MCP3421)& iic驱动库
【软件,模拟iic】
3.1 MCP3421 原理图:
3.2 MCP3421驱动库:
MCP3421.h
#ifndef __MCP3421_H__
#define __MCP3421_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "port_typ.h"
typedef enum
{
gain1 = 0x00 ,
gain2 = 0x01 ,
gain4 = 0x02 ,
gain8 = 0x03
}mcp3421_gain_e ;
typedef enum
{
rate12bit = 0x00 ,
rate14bit = 0x04 ,
rate16bit = 0x08 ,
rate18bit = 0x0C
}mcp3421_rate_e ;
typedef enum
{
oneshot_mode = 0x00 ,
continuous_mode = 0x10 ,
}mcp3421_mode_e;
typedef enum
{
ready = 0x00 ,
nready_or_start = 0x80 ,
}mcp3421_ready_e ;
#define MCP3421_ADDR 0x68
typedef struct
{
uint8_t address ;
uint8_t gain ;
uint8_t sampling_rate ;
uint8_t conversion_mode ;
uint8_t ready_flag ;
}mcp3421_s ;
void mcp3421_init ( mcp3421_s* mcp) ;
void mcp3421_write_rate ( mcp3421_s* mcp, uint8_t rate) ;
void mcp3421_write_gain ( mcp3421_s* mcp, uint8_t gain) ;
void mcp3421_write_mode ( mcp3421_s* mcp, uint8_t mode) ;
void mcp3421_write_flag ( mcp3421_s* mcp, uint8_t flag) ;
uint8_t mcp3421_read_gain ( mcp3421_s* mcp) ;
uint8_t mcp3421_read_rate ( mcp3421_s* mcp) ;
uint8_t mcp3421_read_mode ( mcp3421_s* mcp) ;
uint8_t mcp3421_read_flag ( mcp3421_s* mcp) ;
float mcp3421_one_conversion( mcp3421_s* mcp) ;
void mcp3421_continuous_conversion ( mcp3421_s* mcp, uint8_t times, float *adval) ;
【没实现呢还^0^】
MCP3421.c
#include "mcp3421.h"
#include "port_iic.h"
void mcp3421_init ( mcp3421_s* mcp)
{
mcp->address = MCP3421_ADDR ;
mcp->gain = gain1 ;
mcp->sampling_rate = rate18bit ;
mcp->conversion_mode = oneshot_mode ;
mcp->ready_flag = nready_or_start ;
iic_init() ;//初始化iic
}
void mcp3421_write_gain ( mcp3421_s* mcp, uint8_t gain)
{
mcp->gain = gain ;
}
void mcp3421_write_rate ( mcp3421_s* mcp, uint8_t rate)
{
mcp->sampling_rate = rate ;
}
void mcp3421_write_mode ( mcp3421_s* mcp, uint8_t mode)
{
mcp->conversion_mode = mode ;
}
void mcp3421_write_flag ( mcp3421_s* mcp, uint8_t flag)
{
mcp->ready_flag = flag ;
}
uint8_t mcp3421_read_gain ( mcp3421_s* mcp)
{
return mcp->gain ;
}
uint8_t mcp3421_read_rate ( mcp3421_s* mcp)
{
return mcp->sampling_rate ;
}
uint8_t mcp3421_read_mode ( mcp3421_s* mcp)
{
return mcp->conversion_mode ;
}
uint8_t mcp3421_read_flag ( mcp3421_s* mcp)
{
return mcp->ready_flag ;
}
float mcp3421_one_conversion ( mcp3421_s* mcp)
{
uint8_t cofbit =0 ;
uint8_t ad_buf[3] ;
uint32_t temp = 0 ;
float val = 0 ;
mcp->ready_flag = nready_or_start ; //标志位置1表示转换正在进行或启动单次转换
cofbit = (mcp->gain) | (mcp->sampling_rate) | (mcp->conversion_mode) | (mcp->ready_flag) ; //???
switch (mcp->sampling_rate) //判断:位数-采样率
{
case rate12bit : //12bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 2, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp &= (uint32_t)0x000fff ;
if( (temp >> 11))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x000fff) + 1) * 1.0 ;
val = - val ;
}
else
val = temp * 1.0 ;
break ;
case rate14bit : //14bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 2, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp &= (uint32_t)0x003fff ;
if( (temp >> 13))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x003fff) + 1) * 0.250 ;
val = - val ;
}
else
val = temp * 0.250 ;
break ;
case rate16bit : //16bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 2, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp &= (uint32_t)0x00ffff ;
if( (temp >> 15))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x00ffff) + 1) * 0.0625 ;
val = - val ;
}
else
val = temp * 0.0625 ;
break ;
case rate18bit : //18bit
iic_master_receive ( mcp->address, cofbit, ad_buf, 3, 100) ;
temp = ( temp << 8) | ad_buf[0] ;
temp = ( temp << 8) | ad_buf[1] ;
temp = ( temp << 8) | ad_buf[2] ;
temp &= (uint32_t)0x03ffff ;
if( (temp >> 17))
{
temp = ~temp ;
val = ( ( temp & (uint32_t)0x03ffff) + 1) * 0.015625 ;
val = - val ;
}
else
val = temp * 0.015625 ;
break ;
}
switch(mcp->gain) //判断增益——除以增益还原
{
case gain1 :
val /= 1 ;
break ;
case gain2 :
val /= 2 ;
break ;
case gain4 :
val /= 4 ;
break ;
case gain8 :
val /= 8 ;
break ;
}
return val ;
}
3.3 iic驱动库【模拟iic】:
port_iic.h
#ifndef __PORT_IIC_H
#define __PORT_IIC_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "port_typ.h"
void iic_init (void) ;
uint8_t iic_master_transmit ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout) ;
uint8_t iic_master_receive ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout) ;
port_iic.c
在main.h里定义 SDA SCL的GPIO 宏定义
#define MCP3421_SDA_Pin GPIO_PIN_11
#define MCP3421_SDA_GPIO_Port GPIOA
#define MCP3421_SCL_Pin GPIO_PIN_12
#define MCP3421_SCL_GPIO_Port GPIOA
#include "port_iic.h"
#include "port_delay.h"
#include "gpio.h"
#define I2C_DELAY_US(x) port_delay_us(x)
#define I2C_DELAY_MS(x) port_delay_ms(x)
#define I2C_SCL_SET() HAL_GPIO_WritePin( GPIOA, MCP3421_SCL_Pin, GPIO_PIN_SET)
#define I2C_SCL_RESET() HAL_GPIO_WritePin( GPIOA, MCP3421_SCL_Pin, GPIO_PIN_RESET)
#define I2C_SDA_SET() HAL_GPIO_WritePin( GPIOA, MCP3421_SDA_Pin, GPIO_PIN_SET)
#define I2C_SDA_RESET() HAL_GPIO_WritePin( GPIOA, MCP3421_SDA_Pin, GPIO_PIN_RESET)
#define I2C_SDA_GET() HAL_GPIO_ReadPin( GPIOA, MCP3421_SDA_Pin)
#define I2C_SDA_IN() {GPIOA->CRH&=0xFFFF0FFF;GPIOA->CRH|=0x00008000;}
#define I2C_SDA_OUT() {GPIOA->CRH&=0xFFFF0FFF;GPIOA->CRH|=0x00003000;}
uint8_t iic_txbuf[32] ;
static void iic_start()
{
I2C_SDA_OUT() ;
I2C_SDA_SET() ;
I2C_SCL_SET() ;
I2C_DELAY_US(4) ;
I2C_SDA_RESET() ;
I2C_DELAY_US(4) ;
I2C_SCL_RESET() ;
}
static void iic_stop()
{
I2C_SDA_OUT() ;
I2C_SCL_RESET() ;
I2C_SDA_RESET() ;
I2C_DELAY_US(4) ;
I2C_SCL_SET() ;
I2C_SDA_SET() ;
I2C_DELAY_US(4) ;
}
static void iic_send_byte (uint8_t tx)
{
uint8_t i ;
I2C_SDA_OUT() ;
I2C_SCL_RESET() ;
for ( i = 0; i < 8; i++)
{
if ( tx & 0x80)
{
I2C_SDA_SET() ;
}
else
{
I2C_SDA_RESET() ;
}
tx <<= 1 ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_RESET() ;
I2C_DELAY_US(2) ;
}
}
static uint8_t iic_read_byte()
{
uint8_t i ;
uint8_t res ;
res = 0 ;
I2C_SDA_IN() ;
for ( i = 0; i < 8; i++)
{
I2C_SCL_RESET() ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
res <<= 1 ;
if ( I2C_SDA_GET())
{
res++ ;
}
I2C_DELAY_US(1) ;
}
return res ;
}
static uint8_t iic_wait_ack()
{
uint8_t i ;
I2C_SDA_IN() ;
I2C_SDA_SET() ;
I2C_DELAY_US(1) ;
I2C_SCL_SET() ;
I2C_DELAY_US(1) ;
while ( I2C_SDA_GET())
{
i++ ;
if ( i > 250)
{
iic_stop() ;
return 1 ;
}
}
I2C_SCL_RESET() ;
return 0 ;
}
static void iic_send_ack()
{
I2C_SCL_RESET() ;
I2C_SDA_OUT() ;
I2C_SDA_RESET() ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_RESET() ;
}
static void iic_send_nack()
{
I2C_SCL_RESET() ;
I2C_SDA_OUT() ;
I2C_SDA_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_SET() ;
I2C_DELAY_US(2) ;
I2C_SCL_RESET() ;
}
static void iic_memcpy ( uint8_t *dest, uint8_t *src, uint32_t length)
{
uint32_t i ;
for ( i = 0; i < length; i++)
{
*dest = *src ;
dest++ ;
src++ ;
}
}
void iic_init()
{
}
uint8_t iic_master_transmit ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout)
{
uint16_t i ;
uint32_t j ;
uint8_t rev ;
rev = 0 ;
iic_txbuf[0] = ( ( dev << 1) | 0) ;
iic_txbuf[1] = reg ;
iic_memcpy ( &(iic_txbuf[2]), str, length) ;
length += 2 ;
iic_start() ;
for ( i = 0; i < length; i++)
{
iic_send_byte(iic_txbuf[i]) ;
j = 0 ;
while ( ( iic_wait_ack()) && ( j < timeout))
{
j++ ;
I2C_DELAY_US(5) ;
}
if ( j >= timeout)
{
rev = i + 1 ;
break ;
}
}
iic_stop() ;
return rev ;
}
uint8_t iic_master_receive ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout)
{
uint16_t i = 0 ;
iic_start() ;
iic_send_byte ( ( dev << 1) | 0) ;
if( iic_wait_ack())
{
iic_stop() ;
return 1 ;
}
iic_send_byte(reg) ;
if( iic_wait_ack())
{
iic_stop() ;
return 1 ;
}
iic_start() ;
iic_send_byte( ( dev << 1) | 1) ;
if( iic_wait_ack())
{
iic_stop() ;
return 1 ;
}
length-- ;
for ( ; i < length; i++)
{
str[i] = iic_read_byte() ;
iic_send_ack() ;
}
str[i] = iic_read_byte() ;
iic_send_nack() ;
iic_stop() ;
return 0 ;
}
port_delay.h
提供毫秒和微妙级别的软件延时:
#ifndef __PORT_DELAY_H
#define __PORT_DELAY_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "port_typ.h"
void port_delay_us( uint32_t us) ;
void port_delay_ms( uint32_t ms) ;
port_delay.h
#include "port_delay.h"
#include "tim.h"
void port_delay_us( uint32_t us)
{
uint32_t differ = 0xfff0 - us ;
HAL_TIM_Base_Start(&htim4) ;
__HAL_TIM_SET_COUNTER( &htim4, differ) ;
while( differ < 0xfff0)
{
differ = __HAL_TIM_GET_COUNTER(&htim4) ;
}
HAL_TIM_Base_Stop(&htim4) ;
}
void port_delay_ms( uint32_t ms)
{
HAL_Delay(ms) ;
}
3.4 实现:
①在main中初始化
mcp3421_init(&mcp) ; // 初始化MCP3421---有默认值~18位
②在其他的任务中调用
float voltage1 ;//全局变量
voltage1 = mcp3421_one_conversion(&mcp) ;
4.基础滤波【DMA方式时使用】:
float port_adc_get_vaule(void)
{
float rev = 0 ;
HAL_ADC_Start_DMA( &hadc1, (uint32_t*)port_adc_buf, 2) ;
port_delay_ms(1) ;
rev = ( ( 1.225 * port_adc_buf[0]) / port_adc_buf[1]) ;
return rev ;
}
float port_ad
float av_filter_get_ad()
{
uint8_t j ;
port_ad = 0 ;
port_adc_get_vaule() ;
for ( j = 0; j < 8; j++)
{
port_ad += port_adc_get_vaule() ;
}
port_ad /= 8 ;
return port_ad;
}
5.实训:温度传感器ADC采集:
5.1 way1:DMA
void my_app_init()
{
temp_init() ;
port_adc_init() ;
}
void my_app()
{
uint8_t j ;
port_ad = 0 ;
port_adc_get_vaule() ;
for ( j = 0; j < 8; j++)
{
port_ad += port_adc_get_vaule() ;
}
port_ad /= 8 ;
tep = temp_get_temp( port_ad*1000) ;
pr_info("%s:%d",TAG,tep) ;
port_delay_ms(500) ;
}
int main(void)
{
my_app_init() ;
while (1)
{
my_app() ;
}
}
5.2 way2:外部18位ADC
void my_app_init()
{
mcp3421_init(&mcp) ;
temp_init() ;
}
void my_app()
{
voltage1 = mcp3421_one_conversion(&mcp) ;
tep = temp_get_temp( voltage1) ;
pr_info("%s:%d",TAG,tep) ;
port_delay_ms(1000) ;
}
int main(void)
{
my_app_init() ;
while (1)
{
my_app() ;
}
}