STM32笔记(三)ADC、DMA、USART的综合练习

/******************************************************************************
* 本文件实现ADC模块的基本功能
* 设置ADC1的常规转换序列包含CH10和CH16(片内温度传感器)
* 设置了连续转换模式,并使用DMA传输
* AD转换值被放在了AD_Value[2]数组内,[0]保存CH0结果,[1]保存CH16结果
* GetVolt函数计算[0]的值对应的电压值(放大100倍,保留2位小数)
* GetTemp函数计算[1]的值对应的温度值,计算公式在相应函数内有说明
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"
#include "stdio.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ADC1_DR_Address    ((u32)0x4001244C)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
vu16 AD_Value [ 2 ];
vu16 i = 0;
s16  Temp;
u16  Volt;

/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration( void);
void GPIO_Configuration( void);
void NVIC_Configuration( void);
void USART1_Configuration( void);
void ADC1_Configuration( void);
void DMA_Configuration( void);

int fputc( int ch , FILE * f);
void Delay( void);
u16 GetTemp( u16 advalue);
u16 GetVolt( u16 advalue);
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main( void)
{
    RCC_Configuration();
    GPIO_Configuration();
    NVIC_Configuration();
    USART1_Configuration();
    DMA_Configuration();
    ADC1_Configuration();
   
    //启动第一次AD转换
    ADC_SoftwareStartConvCmd( ADC1 , ENABLE);
    //因为已经配置好了DMA,接下来AD自动连续转换,结果自动保存在AD_Value处  
   
    while ( 1)
    {
        Delay();
        Temp = GetTemp( AD_Value [ 1 ]);
        Volt = GetVolt( AD_Value [ 0 ]);
        USART_SendData( USART1 , 0x0c);       //清屏
        //注意,USART_SendData函数不检查是否发送完成
        //等待发送完成
        while( USART_GetFlagStatus( USART1 , USART_FLAG_TXE) == RESET);

        printf( "电压:%d.%d /t 温度:%d.%d℃ /r/n " , /
            Volt / 100 , Volt % 100 , Temp / 100 , Temp % 100);
       
    }
}

/*******************************************************************************
* Function Name  : 重定义系统putchar函数int fputc(int ch, FILE *f)
* Description    : 串口发一个字节
* Input          : int ch, FILE *f
* Output         :
* Return         : int ch
*******************************************************************************/
int fputc( int ch , FILE * f)
{
    //USART_SendData(USART1, (u8) ch);
    USART1 -> DR = ( u8) ch;
   
    /* Loop until the end of transmission */
    while( USART_GetFlagStatus( USART1 , USART_FLAG_TXE) == RESET)
    {
    }

    return ch;
}

/*******************************************************************************
* Function Name  : Delay
* Description    : 延时函数
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Delay( void)
{
    u32 i;
    for( i = 0; i < 0x4f0000; i ++);
    return;
}                           

/*******************************************************************************
* Function Name  : GetTemp
* Description    : 根据ADC结果计算温度
* Input          : u16 advalue
* Output         :
* Return         : u16 temp
*******************************************************************************/
u16 GetTemp( u16 advalue)
{
    u32 Vtemp_sensor;
    s32 Current_Temp;
   
//    ADC转换结束以后,读取ADC_DR寄存器中的结果,转换温度值计算公式如下:
//          V25 - VSENSE
//  T(℃) = ------------  + 25
//           Avg_Slope
//   V25:  温度传感器在25℃时 的输出电压,典型值1.43 V。
//  VSENSE:温度传感器的当前输出电压,与ADC_DR 寄存器中的结果ADC_ConvertedValue之间的转换关系为:
//            ADC_ConvertedValue * Vdd
//  VSENSE = --------------------------
//            Vdd_convert_value(0xFFF)
//  Avg_Slope:温度传感器输出电压和温度的关联参数,典型值4.3 mV/℃。

    Vtemp_sensor = advalue * 330 / 4096;
    Current_Temp = ( s32)( 143 - Vtemp_sensor) * 1000 / 34 + 2500;
    return ( s16) Current_Temp;
} 


/*******************************************************************************
* Function Name  : GetVolt
* Description    : 根据ADC结果计算电压
* Input          : u16 advalue
* Output         :
* Return         : u16 temp
*******************************************************************************/
u16 GetVolt( u16 advalue)
{
    return ( u16)( advalue * 330 / 4096);
}
                         

/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : 系统时钟设置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration( void)
{
    ErrorStatus HSEStartUpStatus;

    //使能外部晶振
    RCC_HSEConfig( RCC_HSE_ON);
    //等待外部晶振稳定
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    //如果外部晶振启动成功,则进行下一步操作
    if( HSEStartUpStatus == SUCCESS)
    {
        //设置HCLK(AHB时钟)=SYSCLK
        RCC_HCLKConfig( RCC_SYSCLK_Div1);

        //PCLK1(APB1) = HCLK/2
        RCC_PCLK1Config( RCC_HCLK_Div2);

        //PCLK2(APB2) = HCLK
        RCC_PCLK2Config( RCC_HCLK_Div1);
       
        //设置ADC时钟频率
        RCC_ADCCLKConfig( RCC_PCLK2_Div2);

        //FLASH时序控制
        //推荐值:SYSCLK = 0~24MHz   Latency=0
        //        SYSCLK = 24~48MHz  Latency=1
        //        SYSCLK = 48~72MHz  Latency=2
        FLASH_SetLatency( FLASH_Latency_2);
        //开启FLASH预取指功能
        FLASH_PrefetchBufferCmd( FLASH_PrefetchBuffer_Enable);

        //PLL设置 SYSCLK/1 * 9 = 8*1*9 = 72MHz
        RCC_PLLConfig( RCC_PLLSource_HSE_Div1 , RCC_PLLMul_9);
        //启动PLL
        RCC_PLLCmd( ENABLE);
        //等待PLL稳定
        while( RCC_GetFlagStatus( RCC_FLAG_PLLRDY) == RESET);
        //系统时钟SYSCLK来自PLL输出
        RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK);
        //切换时钟后等待系统时钟稳定
        while( RCC_GetSYSCLKSource() != 0x08);

       
    }

    //下面是给各模块开启时钟
    //启动GPIO
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | /
                           RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD , /
                           ENABLE);
    //启动AFIO
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO , ENABLE);
    //启动USART1
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 , ENABLE);
    //启动DMA时钟
    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1 , ENABLE);
    //启动ADC1时钟
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1 , ENABLE);

}


/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : GPIO设置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void GPIO_Configuration( void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    //PC口4567脚设置GPIO输出,推挽 2M
    GPIO_InitStructure . GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure . GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure . GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init( GPIOC , & GPIO_InitStructure);

    //KEY2 KEY3 JOYKEY
    //位于PD口的3 4 11-15脚,使能设置为输入
    GPIO_InitStructure . GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 | /
        GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure . GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init( GPIOD , & GPIO_InitStructure);

    //USART1_TX
    GPIO_InitStructure . GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure . GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure . GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init( GPIOA , & GPIO_InitStructure);
   
    //USART1_RX
    GPIO_InitStructure . GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure . GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init( GPIOA , & GPIO_InitStructure);
   
    //ADC_CH10--> PC0
    GPIO_InitStructure . GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure . GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init( GPIOC , & GPIO_InitStructure);

}



/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : NVIC设置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void NVIC_Configuration( void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM
    // Set the Vector Table base location at 0x20000000
    NVIC_SetVectorTable( NVIC_VectTab_RAM , 0x0);
#else  /* VECT_TAB_FLASH  */
    // Set the Vector Table base location at 0x08000000
    NVIC_SetVectorTable( NVIC_VectTab_FLASH , 0x0);
#endif

    //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
    //串口中断打开
    NVIC_InitStructure . NVIC_IRQChannel = USART1_IRQChannel;
    NVIC_InitStructure . NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure . NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure . NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( & NVIC_InitStructure);
}


/*******************************************************************************
* Function Name  : USART1_Configuration
* Description    : NUSART1设置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USART1_Configuration( void)
{
    USART_InitTypeDef USART_InitStructure;
   
    USART_InitStructure . USART_BaudRate = 19200;
    USART_InitStructure . USART_WordLength = USART_WordLength_8b;
    USART_InitStructure . USART_StopBits = USART_StopBits_1;
    USART_InitStructure . USART_Parity = USART_Parity_No;
    USART_InitStructure . USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure . USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init( USART1 , & USART_InitStructure);
   
    USART_ITConfig( USART1 , USART_IT_RXNE , ENABLE);
   
    USART_Cmd( USART1 , ENABLE);
}

/*******************************************************************************
* Function Name  : ADC1_Configuration
* Description    : ADC1设置(包括ADC模块配置和自校准)
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ADC1_Configuration( void)
{
    ADC_InitTypeDef ADC_InitStructure;

    ADC_InitStructure . ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure . ADC_ScanConvMode = ENABLE;
    ADC_InitStructure . ADC_ContinuousConvMode = ENABLE//连续转换开启
    ADC_InitStructure . ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure . ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure . ADC_NbrOfChannel = 2;     //设置转换序列长度为2
    ADC_Init( ADC1 , & ADC_InitStructure);
   
    //ADC内置温度传感器使能(要使用片内温度传感器,切忌要开启它)
    ADC_TempSensorVrefintCmd( ENABLE);
   
    //常规转换序列1:通道10
    ADC_RegularChannelConfig( ADC1 , ADC_Channel_10 , 1 , ADC_SampleTime_13Cycles5);
    //常规转换序列2:通道16(内部温度传感器),采样时间>2.2us,(239cycles)
    ADC_RegularChannelConfig( ADC1 , ADC_Channel_16 , 2 , ADC_SampleTime_239Cycles5);
   
    // Enable ADC1
    ADC_Cmd( ADC1 , ENABLE);
    // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
    ADC_DMACmd( ADC1 , ENABLE);
   
    // 下面是ADC自动校准,开机后需执行一次,保证精度
    // Enable ADC1 reset calibaration register
    ADC_ResetCalibration( ADC1);
    // Check the end of ADC1 reset calibration register
    while( ADC_GetResetCalibrationStatus( ADC1));

    // Start ADC1 calibaration
    ADC_StartCalibration( ADC1);
    // Check the end of ADC1 calibration
    while( ADC_GetCalibrationStatus( ADC1));
    // ADC自动校准结束---------------
   
}

/*******************************************************************************
* Function Name  : DMA_Configuration
* Description    : DMA设置:从ADC模块自动读转换结果至内存
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void DMA_Configuration( void)
{
    DMA_InitTypeDef DMA_InitStructure;
   
    DMA_DeInit( DMA1_Channel1);
    DMA_InitStructure . DMA_PeripheralBaseAddr = ADC1_DR_Address;
    DMA_InitStructure . DMA_MemoryBaseAddr = ( u32) & AD_Value;
    DMA_InitStructure . DMA_DIR = DMA_DIR_PeripheralSRC;
    //BufferSize=2,因为ADC转换序列有2个通道
    //如此设置,使序列1结果放在AD_Value[0],序列2结果放在AD_Value[1]
    DMA_InitStructure . DMA_BufferSize = 2;
    DMA_InitStructure . DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure . DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure . DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure . DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    //循环模式开启,Buffer写满后,自动回到初始地址开始传输
    DMA_InitStructure . DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure . DMA_Priority = DMA_Priority_High;
    DMA_InitStructure . DMA_M2M = DMA_M2M_Disable;
    DMA_Init( DMA1_Channel1 , & DMA_InitStructure);
    //配置完成后,启动DMA通道
    DMA_Cmd( DMA1_Channel1 , ENABLE);
}

你可能感兴趣的:(STM32)