基于STM32的ADC驱动多通道采集

一、STM32的ADC

        ADC的主要参数:采样时间和分辨率

        STM32的ADC的最高采样速率为1us;

        STM32的分辨率为12位,采样后的值为0-4095。

ADC的初始化代码


 

#include "adc1.h"
#include "sys.h"
#include 

void ADC1_Regular_Init(void)
{
    //光敏电阻初始化
    RCC->APB2ENR |= 1<<3;  
    GPIOB->CRL &= 0XFFFFFFF0;
    //ADC时钟配置
    RCC->APB2ENR |= 1<<9;
    RCC->CFGR &= ~(3<<14);
    RCC->CFGR |= 2<<14;
    
    //ADC复位
    RCC->APB2RSTR |= 1<<9;
    RCC->APB2RSTR &= ~(1<<9);
    
    //ADC相关配置
    ADC1->CR1 &= ~(0XF<<16);  //设置ADC1为独立模式
    ADC1->CR1 |= 1<<8;  //开启扫描模式
    ADC1->CR2 |= 1<<23;  //开启内部温度传感器
    
    ADC1->CR2 |= 1<<20; //使用外部事件触发
    ADC1->CR2 |= 7<<17; //选择SWSTART为外部触发源
    ADC1->CR2 &= ~(1<<11); //数据右对齐
    
    ADC1->CR2 |= 1<<8;  //使用DMA
    ADC1->CR2 &= ~(1<<1);   //开启单次转换
    ADC1->SQR1 &= ~(0xf<<20);  //设置规则通道转换的数目
    ADC1->SQR1 |= 1<<20;
    
    ADC1->SQR3 &= 0XFFFFFC00;
    ADC1->SQR3 |= 8;
    ADC1->SQR3 |= 16<<5;
    
    ADC1->SMPR2 |= 7<<24; //设置采样时间
    ADC1->SMPR1 |= 7<<18;  //设置采样时间
    
    
    //校准
    ADC1->CR2 |= 1<<0; // 开启ADC1
    ADC1->CR2 |= 1<<3; //初始化校准寄存器
    while(ADC1->CR2 & 1<<3);
    ADC1->CR2 |= 1<<2;   //开始校准
    while(ADC1->CR2 & 1<<2);
    

    
}

uint16_t ADC1_GetValue(uint8_t CHx)
{
    //设置ADC1的通道X的采样周期
    if(CHx>=10)
    {
        //设置采样周期为239.5周期
        ADC1->SMPR1 &= ~(7<<(CHx-10)*3);
        ADC1->SMPR1 |= 7<<((CHx-10)*3);   
    }
    else
    {
        //设置采样周期为239.5周期
        ADC1->SMPR2 &= ~(7<<(CHx*3));
        ADC1->SMPR2 |= 7<<(CHx*3);
    }
    //设置ADC1的CHx通道第一个转换并设置序列号
    ADC1->SQR3 &= ~(0x1f<<0);
    ADC1->SQR3 |= (CHx & 0X1F);
    ADC1->CR2 |= 1<<22; //开始转换规则通道
    
    while(!(ADC1->SR & 1<<1));  //等待转换完成
    return ADC1->DR;     //返回转换后的AD值
    
}

void ADC1_Injected_Init(void)
{
    //初始化温度传感器
    RCC->APB2ENR |= 1<<3;  
    GPIOB->CRL &= 0XFFFFFFF0;
    //ADC1时钟配置
    RCC->APB2ENR |= 1<<9;
    RCC->CFGR &= ~(3<<14);
    RCC->CFGR |= 2<<14;    
    //ADC复位
    RCC->APB2RSTR |= 1<<9;
    RCC->APB2RSTR &= ~(1<<9);
    //ADC1相关配置
    ADC1->CR1 &= ~(0XF<<16);  //独立模式
    ADC1->CR1 |= 1<<10; //开启自动的注入通道组转换
    ADC1->CR1 |= 1<<8; //开启扫描模式
    ADC1->CR1 |= 1<<7;  //允许JEOC中断
    CM3_NVIC_SetPriority(ADC1_2_IRQn,1,1);
    
    ADC1->CR2 |= 1<<23;  //启用温度传感器
    
    ADC1->CR2 |= 1<<15; //使用外部事件启动转换
    ADC1->CR2 |= 7<<12; //选择注入通道启动的事件为JSWSTART
    ADC1->CR2 &= ~(1<<11); //数据右对齐
    ADC1->CR2 &= ~(1<<8); //不开启DMA
    ADC1->CR2 &= ~(1<<1);  //单次转换
    
    //设置CH8的采样时间位239.5周期
    ADC1->SMPR2 |= 7<<24;
    
    //设置CH16的采样时间为239.5周期

    ADC1->SMPR1 |= 7<<18;
    
    ADC1->JSQR |= 1<<20;  //2个注入转换通道
    //设置CH8第1个转换
    ADC1->JSQR |= 8<<10;
    ADC1->JSQR |= 16<<15;
    
    
    //复位校准
    
    ADC1->CR2 |= 1<<0; //开启ADC1
    ADC1->CR2 |= 1<<3;  //复位校准
    while(ADC1->CR2 & 1<<3);
    ADC1->CR2 |= 1<<2;  //AD校准
    while(ADC1->CR2 & 1<<2);
        
}

void ADC1_2_IRQHandler(void)
{
    u16 Light;
    u16 AD;
    float VSENSE; //温度AD值对应的电压值
    float V25 = 1.43;        //参考值
    float Avg_Slope = 0.0043; //平均斜率
    float Temp;
    if(ADC1->SR & 1<<2)  //JEOC
    {
        Light = ADC1->JDR1;
        
        AD = ADC1->JDR2;    //CPU温度
        printf("AD = %d\n",AD);
        VSENSE = AD / 4096.0 * 3.3;
        //温度(°C) = {(V25 - VSENSE) / Avg_Slope} + 25
        Temp = ((V25 - VSENSE) / Avg_Slope) + 25;

        printf("light = %d, Temp = %.1f\n", Light, Temp);
        ADC1->SR &= ~(1<<2); //清除JEOC
    }
}

DMA初始化

#include "dma.h"
#include "delay.h"
void DMA1_P2M_Init(uint32_t src,uint32_t des)
{
	RCC->AHBENR |= 1<<0;  //开启DAM1的时钟
	Delay_ms(10);
	
	DMA1_Channel1->CCR &= ~(1<<14);  //非存储器到存储器模式
	DMA1_Channel1->CCR |= 3<<12;        //优先级最高
	DMA1_Channel1->CCR &= ~(3<<10);   //设置存储器数据宽度为16位
	DMA1_Channel1->CCR |= 1<<10;      
	DMA1_Channel1->CCR |= 1<<8;      //设置外设数据位宽度16位
	DMA1_Channel1->CCR |= 1<<7;        //存储器地址增量模式
	DMA1_Channel1->CCR &= ~(1<<6);     //不开启外设地址增量模式
	DMA1_Channel1->CCR &= ~(1<<5);    //不开启循环模式
	DMA1_Channel1->CCR &= ~(1<<4);   //数据传输方向位外设到存储器
	
	DMA1_Channel1->CPAR = src;
	DMA1_Channel1->CMAR = des;
	
	
}

void DMA1_StartUp(uint16_t num)
{
	DMA1_Channel1->CCR &= ~(1<<0);   //关闭传输
	DMA1_Channel1->CNDTR = num;       //传输数量
	DMA1_Channel1->CCR |= 1<<0;      //开始传输
	
}

主函数
 

#include "stm32f10x.h"                  // Device header
#include "led.h"
#include "Delay.h"
#include "Key.h"
#include "exti.h"
#include "BEEP.h"
#include "Usart3.h"
#include "Timer.h"
#include "string.h"
#include "usart.h"
#include "ESP8266.h"
#include "OLED.h"
#include "RTC.h"
#include "ADC1.h"
#include "dma.h"
uint8_t KeyNum ;

int main(void)
{
    uint16_t buff[2];
    Led_Init();
    BEEP_Init();
    Key_Init();
    USART1_Init(115200);
    Timer1_Init(729,10*1000);
    DMA1_P2M_Init((uint32_t)&(ADC1->DR),(uint32_t)buff);
    DMA1_StartUp(2);
    ADC1_Regular_Init();
    ADC1->CR2 |= 1<<22;

    
    BEEP_ON;
    Delay_ms(50);
    BEEP_OFF;
    while(1)
    {
        if(DMA1->ISR & 1<<1)
        {
            printf("ad[0]=%d, ad[1]=%d\n", buff[0], buff[1]);
            DMA1->IFCR |= 1<<1; 
            DMA1_StartUp(2);    
            ADC1->CR2 |= 1<<22; 
        
        }
    }
}

你可能感兴趣的:(c语言,stm32)