Proteus8仿真stm32:ADC转换程序详解

#C0102


沧海茫茫千钟粟,且拾吾昧一微尘

——《沧海拾昧集》@CuPhoenix


【阅前敬告】

沧海拾昧集仅做个人学习笔记之用,所述内容不专业不严谨不成体系

如有问题必是本集记录有谬,切勿深究


目录

一、原理图绘制

二、多位七段数码管

三、ADC引脚

四、代码

 五、仿真问题


一、原理图绘制

ADC转换程序电路原理图

         

图中所用到的元件和元件在库中的名称对照表如下:

元件名 库中名称
可变电阻 POT-HG
STM32F103R6 STM32F103R6
4位7段共阴数码管 7SEG-MPX4-CC
高电平 POWER
GROUND

二、多位七段数码管

1、共阴管是CC,共阳管是CA,对应的译码表如下。

数码管译码表

2、输入信号A~G、DP的有效信号看是共阴还是共阳,对应的片选信号1~4是低电平有效,从左到右依次为第1位至第4位。

片选位数 1 2 3 4
片选码 0x0e00 0x0d00 0x0b00 0x0700

3、输出的示例。数字码0x6f,片选码0x0e00,输出码即二者相加0x0e6f。

GPIO_Write(GPIOC, 0x0e6f );
在第1位输出“9”

4、输出用的函数GPIO_Write的定义如下,适用于对统一端口的多个引脚的写入。

void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t ProtVal)

5、多位七段管输出的方法是动态扫描,即逐位输出。在每位输出前面加一个短暂的延时函数,然后清零引脚,动态扫描输出就不会闪烁了。示例如下(在第一位片选码使用0x0e80,加了个小数点)。

 先定义好译码表待查。

const uint16_t SegmentCodes[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
const uint16_t SegmentBit[]={0x0e80,0x0d00,0x0b00,0x0700};

输出内容。

uint16_t temp = 1234;
                        // 输出内容:1234
uint16_t unit[4];
unit[0] = temp / 1000;
unit[1] = temp % 1000 / 100;
unit[2] = temp % 100 / 10;
unit[3] = temp % 10;
                        // 位数拆分
int i = 0;
for(i=0;i<4;i++){
    delay();
    GPIO_Write(GPIOC, 0x0f00 );
    GPIO_Write(GPIOC, SegmentCodes[unit[i]]+SegmentBit[i] );
}
                        // 循环输出各位

短暂的延时。

void delay(){
	int i=0,j=0;
	for(i=0;i<5;i++){
		for(j=0;j<100;j++){}
	}
}

仿真结果。 

动态扫描输出四位

三、ADC引脚

ADC通道对应的引脚必须正确

图源 @夜路难行々

四、代码

#include "stm32f10x.h"

#define ADC1_DR_Address ((uint32_t)0x4001244C)

ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
__IO uint16_t ADCConvertedValue;
ErrorStatus HSEStartUpStatus;
const uint16_t SegmentCodes[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
                                        // 共阴数码管 0 ~ 9 查码表
const uint16_t SegmentBit[]={0x0e80,0x0d00,0x0b00,0x0700}; 
                                        // 片选 1 ~ 4 查码表

void RCC_Configuration();  // RCC初始化
void GPIO_Configuration();  // GIPO初始化
void delay();


int main(void){
	RCC_Configuration();  
	GPIO_Configuration();
	
	DMA_DeInit(DMA1_Channel1);  // DMA初始化
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;  // 外设地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;  // 存储器地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 1;  // 传输计数器的大小
    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;
    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_Cmd(DMA1_Channel1, ENABLE);
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  // 单ADC触发
    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 = 1;  // 通道个数
    ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
                            // 选择规则组的输入通道,ADC1通道1,采样时钟55.5个周期
	
	ADC_DMACmd(ADC1, ENABLE);
	
	ADC_Cmd(ADC1, ENABLE);  // ADC1使能
	
	ADC_ResetCalibration(ADC1);  
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);  // 校准ADC
	while(ADC_GetCalibrationStatus(ADC1));
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);  // 软件触发ADC
	
	while (1){
		uint16_t temp;
		int i = 0;
		uint16_t unit[4];
		temp = (uint16_t)(((double)(ADCConvertedValue) / (double)0xfff ) * (double)3210);
		//temp = ADCConvertedValue;
		unit[0] = temp / 1000;
		unit[1] = temp % 1000 / 100;
		unit[2] = temp % 100 / 10;
		unit[3] = temp % 10;
		for(i=0;i<4;i++){
				delay();
				GPIO_Write(GPIOC, 0x0f00 );
				GPIO_Write(GPIOC, SegmentCodes[unit[i]]+SegmentBit[i] );
		}
  }

	return 0;
	
}

void RCC_Configuration()
{
	SystemInit();
  RCC_DeInit();

  RCC_HSEConfig(RCC_HSE_ON);

  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    FLASH_SetLatency(FLASH_Latency_2);
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    RCC_PCLK2Config(RCC_HCLK_Div1); 
    RCC_PCLK1Config(RCC_HCLK_Div2);
    RCC_ADCCLKConfig(RCC_PCLK2_Div4); 
  
#ifndef STM32F10X_CL  
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);

#else
    RCC_PREDIV2Config(RCC_PREDIV2_Div5);
    RCC_PLL2Config(RCC_PLL2Mul_8);
    RCC_PLL2Cmd(ENABLE);
    while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
    {}
    RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7);
			
#endif
    RCC_PLLCmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }
	
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
}

void GPIO_Configuration()
{
  GPIO_InitTypeDef GPIO_InitStructure;
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
}

#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{ 
  while (1)
  {
  }
}
#endif

void delay(){
	int i=0,j=0;
	for(i=0;i<5;i++){
		for(j=0;j<100;j++){}
	}
}


 五、仿真问题

输出没有值

         仿真遇到问题。无论如何调节输入,ADC的输出均为0。只有在ADC接VDD时,输出为4095(最大值),接与VDD值相等的激励源值也为0。疑似是ADC没有供电。

        网上的两种解决方法均无效:

        ① 如下配置供电网:

供电网 网络连接到供电网
GND GND / VSS / VSSA
VCC / VDD(电压3.3V) VDD / VDDA
VEE

        ② 使用高版本的Proteus:有说法8.11可以,8.9不行,但笔者用的8.13也不行。

        此问题悬而未决,若有大神路过欢迎赐教!

敬谢诸君。


京华西山之巅。

物联沃分享整理
物联沃-IOTWORD物联网 » Proteus8仿真stm32:ADC转换程序详解

发表评论