打印
[应用相关]

stm32 ADC内部芯片温度打印

[复制链接]
3922|41
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hanzhen654|  楼主 | 2018-8-31 23:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
ADC的用途范围可以说是非常的广泛~甚至是可以说差不多必不可少了~大部分单片机嵌入式系统ADC都基本要用到~包括牛人CZZ也一样!

   STM32自带1-3个ADC模块,采样精度达到了12位,比起当年使用的AVR单片机的10位来说,上了个小档次了~本测试程序采用了ADC DMA的中断方式,这样CPU就可以把ADC的任务交给DMA这个勤劳肯干的部下了,当DMA完成了一次任务之后会产生中断,告诉CPU可以来查收结果了!DMA也是在嵌入式系统中非常常用的,例如在LCD中,数据拷贝中等


沙发
hanzhen654|  楼主 | 2018-8-31 23:33 | 只看该作者
总体编程思路和顺序如下:

1.初始化RCC相关,使得系统有时钟,功能模块如ADC、DMA有时钟。

2.GPIO相关初始化,比如常用的指示灯,ADC的管家要设置为输入等。

3.NVIC向量中断的配置,因为这里使用了DMA中断和中断服务程序编写(下例中暂不使用)

4.DMA配置(下例中暂不使用)

5.ADC初始化

使用特权

评论回复
板凳
hanzhen654|  楼主 | 2018-8-31 23:34 | 只看该作者
void ADC_GPIO_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
GPIO_DeInit(GPIOA);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//设为模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

使用特权

评论回复
地板
hanzhen654|  楼主 | 2018-8-31 23:34 | 只看该作者
void ADC_configuration()
{
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//连续多通道模式
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//单次转换
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//右对齐
ADC_InitStructure.ADC_NbrOfChannel=1;//扫描通道数
ADC_Init(ADC1,&ADC_InitStructure);
//ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_7Cycles5);
ADC_Cmd(ADC1,ENABLE);//使能或者失能指定的ADC
ADC_ResetCalibration(ADC1);//重置指定的ADC的校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//等待校准寄存器初始化
ADC_StartCalibration(ADC1);//开始校准
while(ADC_GetCalibrationStatus(ADC1));//等待校准完成
//ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能指定的ADC的软件转换启动功能
}

使用特权

评论回复
5
hanzhen654|  楼主 | 2018-8-31 23:35 | 只看该作者
u16 GetADCValue(u8 ADC_Channel)//ADC_Channel_x 0~17
{
u16 adc_value;
ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_7Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能指定的ADC的软件转换启动功能
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)==RESET);//检查制定ADC标志位置1与否 ADC_FLAG_EOC 转换结束标志位
adc_value=ADC_GetConversionValue(ADC1);
return adc_value;//返回最近一次ADCx规则组的转换结果
}

使用特权

评论回复
6
hanzhen654|  楼主 | 2018-8-31 23:36 | 只看该作者
使用内部温度传感器时,需要使能温度传感器通道

ADC_TempSensorVrefintCmd(ENABLE);

温度传感器通道号是ADC_Channel_16,此通道的采样时间调到最大,来保证精度;

温度的计算公式如下:



V25、Avg_Slope的典型值分别为1.43、4.3mV/C

TEMP=(1.43-Vsense)/0.0043+25;



TEMP=(1.42 - adc*3.3/4096)*1000/4.35 + 25;//转换为温度值,实际应用中,可考虑用毫伏为单位,避免浮点运算

使用特权

评论回复
7
hanzhen654|  楼主 | 2018-8-31 23:37 | 只看该作者
//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3                                                                                                                                          
void  Adc_Init(void)
{        
        ADC_InitTypeDef ADC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟


        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

        //PA1 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);       

        ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

  
        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
       
        ADC_ResetCalibration(ADC1);        //使能复位校准  
         
        while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
       
        ADC_StartCalibration(ADC1);         //开启AD校准

        while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束

//        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能

}               

使用特权

评论回复
8
hanzhen654|  楼主 | 2018-8-31 23:37 | 只看该作者
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)   
{
          //设置指定ADC的规则组通道,一个序列,采样时间
        ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
  
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能       
         
        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

        return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
}

使用特权

评论回复
9
hanzhen654|  楼主 | 2018-8-31 23:38 | 只看该作者
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;
}        

使用特权

评论回复
10
hanzhen654|  楼主 | 2018-8-31 23:38 | 只看该作者
//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3       
void T_Adc_Init(void)  //ADC通道初始化
{
        ADC_InitTypeDef ADC_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能GPIOA,ADC1通道时钟
  
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //分频因子6时钟为72M/6=12MHz

           ADC_DeInit(ADC1);  //将外设 ADC1 的全部寄存器重设为缺省值

        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器

        ADC_TempSensorVrefintCmd(ENABLE); //开启内部温度传感器
       

        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1

        ADC_ResetCalibration(ADC1);        //重置指定的ADC1的复位寄存器

    while(ADC_GetResetCalibrationStatus(ADC1));        //获取ADC1重置校准寄存器的状态,设置状态则等待

        ADC_StartCalibration(ADC1);         //

        while(ADC_GetCalibrationStatus(ADC1));                //获取指定ADC1的校准程序,设置状态则等待
}

使用特权

评论回复
11
hanzhen654|  楼主 | 2018-8-31 23:39 | 只看该作者
u16 T_Get_Adc(u8 ch)   
        {

        ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道3,第一个转换,采样时间为239.5周期                                      

        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
        return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
        }

使用特权

评论回复
12
hanzhen654|  楼主 | 2018-8-31 23:39 | 只看该作者
//得到ADC采样内部温度传感器的值
//取10次,然后平均
u16 T_Get_Temp(void)
        {
        u16 temp_val=0;
        u8 t;
        for(t=0;t<10;t++)
                {
                temp_val+=T_Get_Adc(ADC_Channel_16);          //TampSensor
                delay_ms(5);
                }
        return temp_val/10;
        }

使用特权

评论回复
13
hanzhen654|  楼主 | 2018-8-31 23:40 | 只看该作者
//获取通道ch的转换值
//取times次,然后平均
u16 T_Get_Adc_Average(u8 ch,u8 times)
{
        u32 temp_val=0;
        u8 t;
        for(t=0;t<times;t++)
        {
                temp_val+=T_Get_Adc(ch);
                delay_ms(5);
        }
        return temp_val/times;
}           

使用特权

评论回复
14
hanzhen654|  楼主 | 2018-8-31 23:41 | 只看该作者
//写寄存器函数
//data:寄存器值
void LCD_WR_REG(u16 data)
{
        LCD_RS_CLR;//写地址  
        LCD_CS_CLR;
        DATAOUT(data);
        LCD_WR_CLR;
        LCD_WR_SET;
        LCD_CS_SET;   
}

使用特权

评论回复
15
hanzhen654|  楼主 | 2018-8-31 23:41 | 只看该作者
//写数据函数
//可以替代LCD_WR_DATAX宏,拿时间换空间.
//data:寄存器值
void LCD_WR_DATAX(u16 data)
{
        LCD_RS_SET;
        LCD_CS_CLR;
        DATAOUT(data);
        LCD_WR_CLR;
        LCD_WR_SET;
        LCD_CS_SET;
}

使用特权

评论回复
16
hanzhen654|  楼主 | 2018-8-31 23:42 | 只看该作者
//读LCD数据
//返回值:读到的值
u16 LCD_RD_DATA(void)
{                                                                                  
        u16 t;
        GPIOB->CRL=0X88888888; //PB0-7  上拉输入
        GPIOB->CRH=0X88888888; //PB8-15 上拉输入
        GPIOB->ODR=0X0000;     //全部输出0

        LCD_RS_SET;
        LCD_CS_CLR;
        //读取数据(读寄存器时,并不需要读2次)
        LCD_RD_CLR;
        if(lcddev.id==0X8989)delay_us(2);//FOR 8989,延时2us                                          
        t=DATAIN;  
        LCD_RD_SET;
        LCD_CS_SET;

        GPIOB->CRL=0X33333333; //PB0-7  上拉输出
        GPIOB->CRH=0X33333333; //PB8-15 上拉输出
        GPIOB->ODR=0XFFFF;    //全部输出高
        return t;  
}

使用特权

评论回复
17
hanzhen654|  楼主 | 2018-8-31 23:42 | 只看该作者
//写寄存器
//LCD_Reg:寄存器编号
//LCD_RegValue:要写入的值
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)
{       
        LCD_WR_REG(LCD_Reg);  
        LCD_WR_DATA(LCD_RegValue);                             
}   

使用特权

评论回复
18
hanzhen654|  楼主 | 2018-8-31 23:42 | 只看该作者
//读寄存器
//LCD_Reg:寄存器编号
//返回值:读到的值
u16 LCD_ReadReg(u16 LCD_Reg)
{                                                                                  
        LCD_WR_REG(LCD_Reg);  //写入要读的寄存器号  
        return LCD_RD_DATA();
}

使用特权

评论回复
19
hanzhen654|  楼主 | 2018-8-31 23:43 | 只看该作者
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
        LCD_WR_REG(lcddev.wramcmd);
}

使用特权

评论回复
20
hanzhen654|  楼主 | 2018-8-31 23:43 | 只看该作者
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{                                                            
        LCD_WR_DATA(RGB_Code);//写十六位GRAM
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

73

主题

1766

帖子

2

粉丝