请教ADC循环模式DMA双缓存区数据丢失

2019-07-20 06:59发布

代码为寄存器版本功能描述:
ADC1工作在连续转换模式下,DMA设置为双缓存区模式,采集数据出现间断有规律的丢失:即每包64个Byte的数据,会出现连续两个包的数据前12个Bytes为0x00,接着两个包的数据完整,反复如此。请问这个问题是怎么导致的呢?
主函数代码如下:
//本代码用于测试ADC数据采集并485传输,写入SD卡
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "mpu.h"  
#include "lcd.h"
#include "sdram.h"
#include "usart3.h"
#include "usart1.h"         
#include "malloc.h"  
#include "key.h"
#include "rs485.h"
#include "nand.h"   
#include "ftl.h"
#include "w25qxx.h"   
#include "sdmmc_sdcard.h"
#include "ff.h"  
#include "exfuns.h"
#include "rtc.h"
#include "adc.h"  //ADC
#include "dma.h"
#include "modules.h"

int main(void)
{   
        u8 led0sta=1;
        u8 t=0,i=0;
        u8 Start_MCL302[5] = {0x00,0x05,0x15,0xBD,0x61};
        float temp;  
       
        UINT bw;
        FIL fsrc; //File objects
        FRESULT fr; //FatFs function common result code
       
        //RTC
        u8 hour,min,sec,ampm,year,month,date,week;
        u8 tbuf[40];
        u8 countmp[4];
        u16 send_count = 0;
       
        Stm32_Clock_Init(432,25,2,9);//设置时钟,216Mhz
    delay_init(216);                        //延时初始化
       
        uart1_init(13.5,9600);                //初始化串口1波特率为9600 ,接收SVP数据       
        uart3_init(54,9600);                //初始化串口3波特率为9600,接收磁罗盘数据
       
       
        LED_Init();                                          //初始化与LED连接的硬件接口
        MPU_Memory_Protection();        //保护相关存储区域
        SDRAM_Init();                                //初始化SDRAM
        LCD_Init();                                        //初始化LCD
        KEY_Init();                                 //按键初始化
        Adc_DMA_Init();                                 //初始化ADC
       
        RS485_Init(54,115200);                //初始化RS485,设置usart2波特率为115200
       
        W25QXX_Init();                                //初始化W25Q256
        my_mem_init(SRAMIN);                //初始化内部内存池
        my_mem_init(SRAMEX);                //初始化外部内存池
        my_mem_init(SRAMTCM);                //初始化TCM内存池

        //RTC时钟
        RTC_Init();                                         //初始化RTC
          POINT_COLOR=RED;
        LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7");
        LCD_ShowString(30,70,200,16,16,"RS485 TEST");       
        LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
       
        POINT_COLOR=BLUE;//设置字体为蓝 {MOD}          
        //
       
        while(SD_Init())//检测不到SD卡
        {
                delay_ms(500);
                LED0(led0sta^=1);//DS0闪烁
        }
        FTL_Init();
        exfuns_init();                                //为fatfs相关变量申请内存       
          f_mount(fs[0],"0:",1);                //挂载SD卡

        RTC_Get_Time(&hour,&min,&sec,&ampm);
        RTC_Get_Date(&year,&month,&date,&week);
        sprintf((char*)tbuf,"0:%2d-%02d%02d%02d.txt",date,hour,min,sec); //利用RTC时钟生成文件名       
        fr = f_open(&fsrc,(char*)tbuf,FA_CREATE_ALWAYS|FA_WRITE|FA_READ); //打开或新建一个.txt文件,可读可写
       
        //激活磁罗盘
        for(t=0;t<5;t++)
        {
                USART3->TDR=Start_MCL302[t];
                while((USART3->ISR&0X40)==0);//等待发送结束
        }

        //使用串口中断接收SVP、磁罗盘数据
       
       
       
//        MYDMA_Config_R(DMA1_Stream1,4,(u32)&USART3->RDR,(u32)USART3_DMARX_BUF0,(u32)USART3_DMARX_BUF1,USART3_BUF_LEN);//USART3_TX:数据流3,4号通道;USART3_RX:数据流1,4号通道。       
//        MYDMA_Enable(DMA1_Stream1,USART3_BUF_LEN);//磁罗盘数DMA接收使能
//       
        MYDMA_ADC_Config(DMA2_Stream0,0,(u32)&ADC1->DR,(u32)ADC_DMARX_BUF0,(u32)ADC_DMARX_BUF1,ADC_BUF_LEN);//ADC1MA2数据流0和4,通道0;ADC2MA2数据流2和3,通道1;ADC3MA2数据流0和1,通道2
        MYDMA_Enable(DMA2_Stream0,ADC_BUF_LEN);//开启一次DMA传输
       
       
        //RS485数据传输
        MYDMA_Config_T(DMA1_Stream6,4,(u32)&USART2->TDR,(u32)rs485buf,RS485_TX_LEN);//USART2_TX:数据流6,4号通道;USART2_RX:数据流5,4号通道。
        Get_DMA_Adc(ADC_CH5);
       
        while(1)
        {
                if(ADC1->SR&(1<<5))
                {
                       
                        MYDMA_ADC_Config(DMA2_Stream0,0,(u32)&ADC1->DR,(u32)ADC_DMARX_BUF0,(u32)ADC_DMARX_BUF1,ADC_BUF_LEN);
                        ADC1->SR&=~(1<<5);//ADC_SR寄存器中ADC_OVER位清空
                        Get_DMA_Adc(ADC_CH5);       
                }

                memcpy(countmp,&send_count,2);
               
                rs485buf[RS485_TX_LEN-1] = countmp[0];
                rs485buf[RS485_TX_LEN-2] = countmp[1];
                       
                RTC_Get_Time(&hour,&min,&sec,&ampm);//获取时钟信息
                RTC_Get_Date(&year,&month,&date,&week);//
               
                rs485buf[RS485_TX_LEN-6] = date;
                rs485buf[RS485_TX_LEN-5] = hour;
                rs485buf[RS485_TX_LEN-4] = min;
                rs485buf[RS485_TX_LEN-3] = sec;
               
                while(ADC_BUF_OK==0);
                ADC_BUF_OK=0;
                RS485_TX_Set(1);                        //设置为发送模式
               
                MYDMA_Enable(DMA1_Stream6,RS485_TX_LEN);//开启一次DMA传输

                //memset(rs485buf,0,RS485_TX_LEN); //clean the buf
               
                f_sync(&fsrc); // 刷新文件存储区域的数据信息,将数据真正写入磁盘
                       
                //1M数据 8192
                if(send_count<8192)          
                       
                {
                        fr = f_write(&fsrc,rs485buf,RS485_TX_LEN,&bw);
                        f_sync(&fsrc); // 刷新文件存储区域的数据信息,将数据真正写入磁盘
                        send_count++;

                       
                        while((DMA1->HISR&(1<<21))==0);//等待USART2发送结束
                        DMA1->HIFCR|=1<<21;                                //清除中断标志
                       
                       
                        RS485_RX_CNT=0;          
                        RS485_TX_Set(0);                        //设置为接收模式       
                       
                }       
                else
                {       
                        fr = f_write(&fsrc,rs485buf,RS485_TX_LEN,&bw);
               
                        while((DMA1->HISR&(1<<21))==0);//等待USART2发送结束
                        DMA1->HIFCR|=1<<21;                                //清除中断标志
               
                        RS485_RX_CNT=0;          
                        RS485_TX_Set(0);                        //设置为接收模式       
               
                        f_sync(&fsrc); // 刷新文件存储区域的数据信息,将数据真正写入磁盘
                        f_close(&fsrc);       
                       
                        RTC_Get_Time(&hour,&min,&sec,&ampm);
                        sprintf((char*)tbuf,"0:%2d-%02d%02d%02d.txt",date,hour,min,sec); //利用RTC时钟生成文件名       
                        fr = f_open(&fsrc,(char*)tbuf,FA_CREATE_ALWAYS|FA_WRITE|FA_READ); //打开或新建一个.txt文件,可读可写               
                        send_count=0;

                }
               
        }
}

DMA通道配置:
       
#include "dma.h"                                                                                                                                                     
#include "delay.h"       
#include "sys.h"
#include "usart3.h"
//////////////////////////////////////////////////////////////////////////////////         
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32开发板
//DMA 驱动代码          
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/7/14
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved                                                                          
//////////////////////////////////////////////////////////////////////////////////          

//当NVIC_Group为0时,NVIC_PreemptionPriority必须为0,NVIC_SubPriority可以为0~15
//当NVIC_Group为1时,NVIC_PreemptionPriority可以为0~1,NVIC_SubPriority可以为0~7
//当NVIC_Group为2时,NVIC_PreemptionPriority可以为0~3,NVIC_SubPriority可以为0~3
//当NVIC_Group为3时,NVIC_PreemptionPriority可以为0~7,NVIC_SubPriority可以为0~1
//当NVIC_Group为4时,NVIC_PreemptionPriority可以为0~15,NVIC_SubPriority必须为0

//DMAx的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//chxMA通道选择,范围:0~7
//par:外设地址
//mar:存储器地址
//ndtr:数据传输量  
u8  USART3_DMARX_BUF0[USART3_BUF_LEN];
u8  USART3_DMARX_BUF1[USART3_BUF_LEN];

u16  ADC_DMARX_BUF0[ADC_BUF_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
u16  ADC_DMARX_BUF1[ADC_BUF_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符

u8        USRAT3_BUF_OK=0;
u8         ADC_BUF_OK=0;

u8 rs485buf[RS485_TX_LEN];

void MYDMA_Config_T(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 par,u32 mar0,u16 ndtr)
{
        DMA_TypeDef *DMAx;
        u8 streamx;
        if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
                DMAx=DMA2;
                RCC->AHB1ENR|=1<<22;//DMA2时钟使能
        }else
        {
                DMAx=DMA1;
                RCC->AHB1ENR|=1<<21;//DMA1时钟使能
        }
        while(DMA_Streamx->CR&0X01);//等待DMA可配置
        streamx=(((u32)DMA_Streamx-(u32)DMAx)-0X10)/0X18;                //得到stream通道号
        if(streamx>=6)DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16);        //清空之前该stream上的所有中断标志
        else if(streamx>=4)DMAx->HIFCR|=0X3D<<6*(streamx-4);    //清空之前该stream上的所有中断标志
        else if(streamx>=2)DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);//清空之前该stream上的所有中断标志
        else DMAx->LIFCR|=0X3D<<6*streamx;                                                //清空之前该stream上的所有中断标志
       
        DMA_Streamx->AR=par;                //DMA外设地址
        DMA_Streamx->M0AR=mar0;                //DMA 存储器0地址
        DMA_Streamx->NDTR=ndtr;                //DMA 数据项数
        DMA_Streamx->CR=0;                        //先全部复位CR寄存器值
       
        DMA_Streamx->CR|=1<<6;                //存储器到外设模式
        DMA_Streamx->CR|=0<<8;                //非循环模式
        DMA_Streamx->CR|=0<<9;                //外设非增量模式
        DMA_Streamx->CR|=1<<10;                //存储器增量模式
        DMA_Streamx->CR|=0<<11;                //外设数据长度:8位
        DMA_Streamx->CR|=0<<13;                //存储器数据长度:8位
        DMA_Streamx->CR|=1<<17;                //高等优先级
       
        DMA_Streamx->CR|=0<<21;                //外设突发单次传输
        DMA_Streamx->CR|=0<<23;                //存储器突发单次传输
        DMA_Streamx->CR|=(u32)chx<<25;//通道选择
       
        //DMA_Streamx->FCR=0X21;        //FIFO控制寄存器
}
void MYDMA_Config_R(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 par,u32 mar0,u32 mar1,u16 ndtr)
{
        DMA_TypeDef *DMAx;
        u8 streamx;
        if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
                DMAx=DMA2;
                RCC->AHB1ENR|=1<<22;//DMA2时钟使能
        }else
        {
                DMAx=DMA1;
                RCC->AHB1ENR|=1<<21;//DMA1时钟使能
        }
        while(DMA_Streamx->CR&0X01);//等待DMA可配置
        streamx=(((u32)DMA_Streamx-(u32)DMAx)-0X10)/0X18;                //得到stream通道号
        if(streamx>=6)DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16);        //清空之前该stream上的所有中断标志
        else if(streamx>=4)DMAx->HIFCR|=0X3D<<6*(streamx-4);    //清空之前该stream上的所有中断标志
        else if(streamx>=2)DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);//清空之前该stream上的所有中断标志
        else DMAx->LIFCR|=0X3D<<6*streamx;                                                //清空之前该stream上的所有中断标志
       
        DMA_Streamx->AR=par;                //DMA外设地址
        DMA_Streamx->M0AR=mar0;                //DMA 存储器0地址
        DMA_Streamx->M1AR=mar1;                //DMA 存储器1地址
        DMA_Streamx->NDTR=ndtr;                //DMA 数据项数
        DMA_Streamx->CR=0;                        //先全部复位CR寄存器值
       
        DMA_Streamx->CR|=0<<6;                //外设到存储器模式
        DMA_Streamx->CR|=1<<8;                //循环模式,双缓存区模式下,自动使能循环模式
        DMA_Streamx->CR|=0<<9;                //外设非增量模式
        DMA_Streamx->CR|=1<<10;                //存储器增量模式
        DMA_Streamx->CR|=0<<11;                //外设数据长度:8位
        DMA_Streamx->CR|=0<<13;                //存储器数据长度:8位
       
        DMA_Streamx->CR|=1<<17;                //高等优先级
        DMA_Streamx->CR|=1<<18;                //双缓存区模式
        DMA_Streamx->CR|=0<<21;                //外设突发单次传输
        DMA_Streamx->CR|=0<<23;                //存储器突发单次传输
        DMA_Streamx->CR|=(u32)chx<<25;//通道选择
        //DMA_Streamx->FCR=0X21;        //FIFO控制寄存器
       
        DMA_Streamx->CR|=1<<4;                //传输完成中断使能
        MY_NVIC_Init(0,0,DMA1_Stream1_IRQn,2);//组2,最高优先级
}
void MYDMA_ADC_Config(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 par,u32 mar0,u32 mar1,u16 ndtr)
{
        DMA_TypeDef *DMAx;
        u8 streamx;
        if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
                DMAx=DMA2;
                RCC->AHB1ENR|=1<<22;//DMA2时钟使能
        }else
        {
                DMAx=DMA1;
                RCC->AHB1ENR|=1<<21;//DMA1时钟使能
        }
        while(DMA_Streamx->CR&0X01);//等待DMA可配置
        streamx=(((u32)DMA_Streamx-(u32)DMAx)-0X10)/0X18;                //得到stream通道号
        if(streamx>=6)DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16);        //清空之前该stream上的所有中断标志
        else if(streamx>=4)DMAx->HIFCR|=0X3D<<6*(streamx-4);    //清空之前该stream上的所有中断标志
        else if(streamx>=2)DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);//清空之前该stream上的所有中断标志
        else DMAx->LIFCR|=0X3D<<6*streamx;                                                //清空之前该stream上的所有中断标志
       
        DMA_Streamx->AR=par;                //DMA外设地址
        DMA_Streamx->M0AR=mar0;                //DMA 存储器0地址
        DMA_Streamx->M1AR=mar1;                //DMA 存储器1地址
        DMA_Streamx->NDTR=ndtr;                //DMA 数据项数
        DMA_Streamx->CR=0;                        //先全部复位CR寄存器值
       
        DMA_Streamx->CR|=0<<6;                //外设到存储器模式
        DMA_Streamx->CR|=1<<8;                //循环模式
        DMA_Streamx->CR|=0<<9;                //外设非增量模式
        DMA_Streamx->CR|=1<<10;                //存储器增量模式
        DMA_Streamx->CR|=1<<11;                //外设数据长度:16位
        DMA_Streamx->CR|=1<<13;                //存储器数据长度:16位
        DMA_Streamx->CR|=1<<16;                //中等优先级
        DMA_Streamx->CR|=1<<18;                //双缓冲区模式
        DMA_Streamx->CR|=0<<21;                //外设突发单次传输
        DMA_Streamx->CR|=0<<23;                //存储器突发单次传输
        DMA_Streamx->CR|=(u32)chx<<25;//通道选择
        //DMA_Streamx->FCR=0X21;        //FIFO控制寄存器
       
        DMA_Streamx->CR|=1<<4;                //传输完成中断使能
        MY_NVIC_Init(1,1,DMA2_Stream0_IRQn,2);//组2,最高优先级
}
//开启一次DMA传输
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量  
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
        DMA_Streamx->CR&=~(1<<0);         //关闭DMA传输
        while(DMA_Streamx->CR&0X1);        //确保DMA可以被设置  
        DMA_Streamx->NDTR=ndtr;                //DMA 存储器0地址
        DMA_Streamx->CR|=1<<0;                //开启DMA传输
}          


void DMA1_Stream1_IRQHandler(void)
{
        u8 i=0;
#if SYSTEM_SUPPORT_OS                 //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
        OSIntEnter();
#endif
       
        if(DMA1->LISR&(1<<11))//数据传输完成
        {       
                DMA1->LIFCR|=1<<11;//清除中断状态
                switch(DMA1_Stream1->CR&(1<<19))
                {
                        case 0://DMA 存储器0地址被占用,将1中数据搬移
                                for(i=0;i<USART3_BUF_LEN;i++)
                                rs485buf=USART3_DMARX_BUF1;
                                USRAT3_BUF_OK=1;
                                break;
                        case 0x80000://DMA 存储器1地址被占用,将0中数据搬移
                                for(i=0;i<USART3_BUF_LEN;i++)
                                rs485buf=USART3_DMARX_BUF0;
                                USRAT3_BUF_OK=1;
                                break;
                }
               
          }
               
         
#if SYSTEM_SUPPORT_OS         //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
        OSIntExit();                                                                                           
#endif

}

void DMA2_Stream0_IRQHandler(void)
{
        u8 i=0;
        u8 len=0;
#if SYSTEM_SUPPORT_OS                 //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
        OSIntEnter();
#endif
       
        if(DMA2->LISR&(1<<5))//数据传输完成
        {       
               
                DMA2->LIFCR|=1<<5;//清除中断状态
                switch(DMA2_Stream0->CR&(1<<19))
                {
                        case 0x0://DMA 存储器0地址被占用,将1中数据搬移
                                for(i=0;i<ADC_BUF_LEN;i++)
                               
                                {
                                        rs485buf[2*i+41] = ADC_DMARX_BUF1>>8;//高8位
                                        rs485buf[2*i+42] = ADC_DMARX_BUF1&0xFF;//低8位
                                }
                                if(USART3_RX_STA&0x8000)
                                {                                          
                                        len=USART3_RX_STA&0x3fff;//得到此次接收到的数据长度
                                       
                                        for(i=0;i<len;i++)
                                        rs485buf=USART3_RX_BUF;  //接收缓冲区
                                        USART3_RX_STA=0;    //复位接收状态
                                }
                               
                                ADC_BUF_OK=1;
                                break;
                               
                        case 0x80000://DMA 存储器1地址被占用,将0中数据搬移
                                for(i=0;i<ADC_BUF_LEN;i++)
                               
                                {
                                        rs485buf[2*i+41] = ADC_DMARX_BUF0>>8;//高8位
                                        rs485buf[2*i+42] = ADC_DMARX_BUF0&0xFF;//低8位
                                }
                                if(USART3_RX_STA&0x8000)
                                {                                          
                                        len=USART3_RX_STA&0x3fff;//得到此次接收到的数据长度
                                       
                                        for(i=0;i<len;i++)
                                        rs485buf=USART3_RX_BUF;  //接收缓冲区
                                        USART3_RX_STA=0;    //复位接收状态
                                }
                               
                                ADC_BUF_OK=1;
                                break;
                               
                }
               
          }
               
         
#if SYSTEM_SUPPORT_OS         //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
        OSIntExit();                                                                                           
#endif

}






ADC1配置:
#include "adc.h"
#include "delay.h"                 
//////////////////////////////////////////////////////////////////////////////////         
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32开发板
//ADC 驱动代码          
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/7/13
//版本:V1.1
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved               
//********************************************************************************
//20160713 V1.1
//1,修改Adc_Init函数,支持内部温度传感器数据采集.
//2,新增Get_Temprate函数,用于获取内部温度传感器采集到的温度值
//////////////////////////////////////////////////////////////////////////////////          


//初始化ADC
//这里我们仅以规则通道为例
//我们开启了ADC1_CH5和内部温度传感器通道(CH18)                                                                                                                                  
void  Adc_DMA_Init(void)
{   
        //先初始化IO口
        RCC->APB2ENR|=1<<8;            //使能ADC1时钟
        RCC->AHB1ENR|=1<<0;            //使能PORTA时钟          
        GPIO_Set(GPIOA,PIN5,GPIO_MODE_AIN,0,0,GPIO_PUPD_PU);        //PA5,模拟输入,下拉   

        RCC->APB2RSTR|=1<<8;           //ADCs复位
        RCC->APB2RSTR&=~(1<<8);        //复位结束         
        ADC->CCR=2<<16;                        //ADCCLK=PCLK2/6=6.75/6=1.125Mhz,ADC时钟最好不要超过36Mhz

        ADC->CCR|=1<<23;                //使能内部温度传感器
       
        ADC1->CR1=0;                           //CR1设置清零
        ADC1->CR2=0;                           //CR2设置清零
        ADC1->CR1|=0<<24;              //12位模式
        ADC1->CR1|=0<<8;            //非扫描模式       
       
        ADC1->CR2|=(1<<1);            //连续转换模式
        ADC1->CR2&=~(1<<11);           //右对齐       
        ADC1->CR2|=0<<28;            //软件触发
       
        ADC1->CR2|=1<<9;            //DMA禁止选择,只要发生数据转换且DMA=1,便会发出DMA请求。
       
        ADC1->SQR1&=~(0XF<<20);
        ADC1->SQR1|=0<<20;             //1个转换在规则序列中 也就是只转换规则序列1                           
        //设置通道5的采样时间
        ADC1->SMPR2&=~(7<<(3*5));                //通道5采样时间清空          
        ADC1->SMPR2|=7<<(3*5);                         //通道5  480个周期,提高采样时间可以提高精确度       

        ADC1->SMPR1&=~(7<<(3*(18-10))); //清除通道18原来的设置         
        ADC1->SMPR1|=7<<(3*(18-10));           //通道18 480周期,提高采样时间可以提高精确度,采样率2.34375kHz
       
        ADC1->CR2|=1<<0;                                   //开启AD转换器
        ADC1->CR2|=1<<8;                            //DMA使能
}                                          
//获得ADC值
//ch:通道值 0~18
//返回值:转换结果
void Get_DMA_Adc(u8 ch)   
{
        //设置转换序列                           
        ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch
        ADC1->SQR3|=ch;                                              
        ADC1->CR2|=1<<30;       //启动规则转换通道
        //while(!(ADC1->SR&1<<1));//等待转换结束                   
        //return ADC1->DR;                //返回adc值       
}

u16 Get_Adc(u8 ch)   
{
        //设置转换序列                           
        ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch
        ADC1->SQR3|=ch;                                              
        ADC1->CR2|=1<<30;       //启动规则转换通道
        while(!(ADC1->SR&1<<1));//等待转换结束                   
        return ADC1->DR;                //返回adc值       
}
//获取通道ch的转换值,取times次,然后平均
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
        u32 temp_val=0;
        u8 t;
        for(t=0;t<times;t++)
        {
                temp_val+=Get_Adc(ch);
                delay_ms(5);
        }
        return temp_val/times;
}  
//得到温度值
//返回值:温度值(扩大了100倍,单位:℃.)
short Get_Temprate(void)
{
        u32 adcx;
        short result;
        double temperate;
        adcx=Get_Adc_Average(ADC_CH_TEMP,20);        //读取通道18,20次取平均
        temperate=(float)adcx*(3.3/4096);                //电压值
        temperate=(temperate-0.76)/0.0025+25;         //转换为温度值
        result=temperate*=100;                                        //扩大100倍.
        return result;
}









































友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。