进阶HAL库开发——第一集 :ADC采集

   日期:2020-10-06     浏览:94    评论:0    
核心提示: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默认给Enab

进阶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() ;
  }
}
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服