進階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
/*******************Define to prevent recursive inclusion **********/
#ifndef __MCP3421_H__
#define __MCP3421_H__
#ifdef __cplusplus
extern "C" {
#endif
/****************************Includes********************************/
#include "main.h"
#include "port_typ.h"
/****************************定義***********************************/
typedef enum /* 增益 */
{
gain1 = 0x00 ,
gain2 = 0x01 ,
gain4 = 0x02 ,
gain8 = 0x03
}mcp3421_gain_e ;
typedef enum /* 轉換速率 */
{
rate12bit = 0x00 , /* 240SPS */
rate14bit = 0x04 , /* 60SPS */
rate16bit = 0x08 , /* 15SPS */
rate18bit = 0x0C /* 3.75SPS */
}mcp3421_rate_e ;
typedef enum /* 轉換模式 */
{
oneshot_mode = 0x00 , /* 單次轉換模式 */
continuous_mode = 0x10 , /* 連續轉換模式 */
}mcp3421_mode_e;
typedef enum /* 轉換標志位 */
{
ready = 0x00 , /*0表示轉換結束資料待讀取、*/
nready_or_start = 0x80 , /*1表示轉換正在進行或啟動單次轉換*/
}mcp3421_ready_e ;
/**************************定義結構體*************************************/
/** mcp3421結構體
*
* -address 地址————————————————————默認為 MCP3421_ADDR
* -gain 增益————————————————————默認為1倍增益
【可取1、2、4、8】 @ref mcp3421_gain_e
* -sampling_rate 采樣率————————————默認3.75 SPS (18 bits)
【可取240 SPS (12 bits)、60 SPS (14 bits)、15 SPS (16 bits)】@ref mcp3421_rate_e
* -conversion_mode 轉換模式————————默認One-Shot Conversion
【可取Continuous Conversion、One-Shot Conversion】@ref mcp3421_mode_e
* -ready_flag 狀態標志位
* 【 0表示轉換結束資料待讀取、1表示轉換正在進行或啟動單次轉換 】@ref 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 ;
/*******************************************************
* FunctionName : mcp3421_init()
* Description : 初始化mcp3421,完成iic硬體初始化和mcp3421引數的基本配置
* EntryParameter : mcp mcp3421句柄
* ReturnValue : None
********************************************************/
void mcp3421_init ( mcp3421_s* mcp) ;
/*******************************************************
* FunctionName : mcp3421_write_xxx()
* Description : 修改mcp3421的xxx,在呼叫mcp3421_one_conversion函式時完成引數的正式寫入
* EntryParameter : mcp mcp3421句柄、xxx
* ReturnValue : None
********************************************************/
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) ;
/*******************************************************
* FunctionName : mcp3421_read_xxx()
* Description : 讀取mcp3421的xxx
* EntryParameter : mcp mcp3421句柄
* ReturnValue : 回傳mcp3421的xxx
********************************************************/
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) ;
/*******************************************************
* FunctionName : mcp3421_one_conversion()
* Description : 設定mcp3421為單次轉換并讀取轉換后的資料, 使用mcp中的引數配置mcap3421并開始單次轉換
* EntryParameter : mcp mcp3421句柄
* ReturnValue : 轉換結果,單位為V,范圍-2.048--+(2.048-1LSB)
********************************************************/
float mcp3421_one_conversion( mcp3421_s* mcp) ;
/*******************************************************
* FunctionName : mcp3421_continuous_conversion()
* Description : 設定mcp3421為連續轉換并讀取轉換后的資料,使用mcp中的引數配置mcap3421并開始連續轉換
* EntryParameter : mcp mcp3421句柄
* ReturnValue : 轉換結果,單位為V,范圍-2.048--+(2.048-1LSB)
********************************************************/
void mcp3421_continuous_conversion ( mcp3421_s* mcp, uint8_t times, float *adval) ;
【沒實作呢還^0^】
MCP3421.c
/**************************Includes*************************************/
#include "mcp3421.h"
#include "port_iic.h"
/*************************函式實作************************************/
/* MCP3421初始化 */
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 ;
}
/* 獲得MCP3421的單次轉換結果,ad轉換結果,范圍-2.048--+(2.048-1LSB)單位V */
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
/******************** Define to prevent recursive inclusion**************/
#ifndef __PORT_IIC_H
#define __PORT_IIC_H
#ifdef __cplusplus
extern "C" {
#endif
/*************************** Includes ***********************************/
#include "main.h"
#include "port_typ.h"
/*******************************************************
* FunctionName : mcp3421_init()
* Description : 初始化iic【無具體實作~擺設】
* EntryParameter : None
* ReturnValue : None
********************************************************/
void iic_init (void) ;
/*******************************************************
* FunctionName : mcp3421_init()
* Description : iic主機寫資料,向指定從設備的暫存器寫入一定數量的資料
* EntryParameter :
* @param[in] dev 從設備號
* @param[in] reg 暫存器地址
* @param[in] str 指向帶寫入資料的指標
* @param[in] length 資料長度
* @param[in] timeout 單個資料寫入的超時時間
* ReturnValue :
* -0 寫成功
* -other 第i個字符寫入時出錯
********************************************************/
uint8_t iic_master_transmit ( uint8_t dev, uint8_t reg, uint8_t *str, uint16_t length, uint32_t timeout) ;
/*******************************************************
* FunctionName : mcp3421_init()
* Description : iic主機讀資料,從指定從設備的暫存器讀出一定數量的資料
* EntryParameter :
* @param[in] dev 從設備號
* @param[in] reg 暫存器地址
* @param[in] str 接收資料指標
* @param[in] length 資料長度
* @param[in] timeout 單個資料讀取的超時時間
* ReturnValue :
* -0 寫成功
* -other 第i個字符寫入時出錯
********************************************************/
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
/*************************** Includes ***********************************/
#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;} /* PA11輸入模式 */
#define I2C_SDA_OUT() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=0X00003000;} /* PA11輸出模式 */
/*************************** 用戶自定義變數 ***********************************/
uint8_t iic_txbuf[32] ;
/*******************************************************
* Description : 發送iic起始信號
********************************************************/
static void iic_start()
{
/* 當 SCL 高電平時,SDA 出現一個下跳沿表示 I2C 總線啟動信號 */
I2C_SDA_OUT() ;
I2C_SDA_SET() ;
I2C_SCL_SET() ;
I2C_DELAY_US(4) ;
I2C_SDA_RESET() ;
I2C_DELAY_US(4) ;
I2C_SCL_RESET() ;
}
/*******************************************************
* Description : iic發送結束信號
********************************************************/
static void iic_stop()
{
/* 當 SCL 高電平時,SDA 出現一個上跳沿表示 I2C 總線停止信號 */
I2C_SDA_OUT() ;
I2C_SCL_RESET() ;
I2C_SDA_RESET() ;
I2C_DELAY_US(4) ;
I2C_SCL_SET() ;
I2C_SDA_SET() ;
I2C_DELAY_US(4) ;
}
/*******************************************************
* Description : 發送一個位元組
********************************************************/
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) ;
}
}
/*******************************************************
* Description : iic讀一個位元組
********************************************************/
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 ;
}
/*******************************************************
* Description : iic等待應答信號
********************************************************/
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 ;
}
/*******************************************************
* Description : iic發送應答信號
********************************************************/
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() ;
}
/*******************************************************
* Description : 拷貝函式
從源記憶體地址的起始位置開始拷貝若干個位元組到目標記憶體地址中,即從源source中拷貝n個位元組到目標destin中,
********************************************************/
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++ ;
}
}
/*******************************************************
* Description : iic初始化【擺個樣子】
********************************************************/
void iic_init()
{
}
/*******************************************************
* Description : iic主機寫 資料
回傳0寫成功,回傳其他,則在寫第i個資料的時候超時
********************************************************/
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 ;
}
/*******************************************************
* Description : iic主機讀 資料
回傳0寫成功,回傳其他,則在寫第i個資料的時候超時
********************************************************/
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
提供毫秒和微妙級別的軟體延時:
/************Define to prevent recursive inclusion ******/
#ifndef __PORT_DELAY_H
#define __PORT_DELAY_H
#ifdef __cplusplus
extern "C" {
#endif
/*****************Includes******************/
#include "main.h"
#include "port_typ.h"
/*****************微妙延時*****************/
void port_delay_us( uint32_t us) ;
/*****************毫秒延時*****************/
void port_delay_ms( uint32_t ms) ;
port_delay.h
/*****************Includes******************/
#include "port_delay.h"
#include "tim.h"
/*******************************************************
* Description : 微妙延時
********************************************************/
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) ;
}
/*******************************************************
* Description : 毫秒延時
********************************************************/
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方式時使用】:
/*******************************************************
* Description : 讀取adc轉換結果,阻塞式輪詢實作,必須實作
********************************************************/
float port_adc_get_vaule(void)
{
float rev = 0 ;
/* 單次轉換+DMA傳輸+內部參考電壓校準資料 */
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 ;
}
/*******************************************************
* Description : 采集八次做平均濾波
********************************************************/
float port_ad
float av_filter_get_ad()
{
uint8_t j ;
port_ad = 0 ; /* 重裝在adc值 */
port_adc_get_vaule() ; /* 舍去第一次啟動adc采集到的值 */
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() ; /* 初始化adc ---其實已經在hal庫初始了 */
}
/* 應用程式 */
void my_app()
{
uint8_t j ;
port_ad = 0 ; /* 重裝在adc值 */
port_adc_get_vaule() ; /* 舍去第一次啟動adc采集到的值 */
for ( j = 0; j < 8; j++)
{
port_ad += port_adc_get_vaule() ; /* 采集八次做平均濾波 */
}
port_ad /= 8 ;
tep = temp_get_temp( port_ad*1000) ; /* 轉換成mv */
pr_info("%s:%d",TAG,tep) ; /* 列印溫度,放大了100倍 */
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) ; /* 初始化MCP3421 */
temp_init() ; /* 初始化溫度傳感器 */
}
/* 應用程式 */
void my_app()
{
voltage1 = mcp3421_one_conversion(&mcp) ;
tep = temp_get_temp( voltage1) ;
pr_info("%s:%d",TAG,tep) ; /* 列印溫度,放大了100倍 */
port_delay_ms(1000) ;
}
int main(void)
{
my_app_init() ;
while (1)
{
my_app() ;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/158805.html
標籤:其他
下一篇:AD20.0.13初學










