打印
[STM32F1]

ADC多通道采集,DMA传输,LCD显示

[复制链接]
2903|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 frank_1019 于 2014-3-4 19:39 编辑

改程序对小白就是内伤啊……这个程序不知道到底问题在哪。

在LCD上的显示,数字量一直闪变,模拟量一直为0.000V。
用Jlink调试,temp竟然出现负值了,不知道到底是什么原因,各种求指导啊


//////////////////////////////////////////////////////////////////

//多通道ADC,选用ADC1的通道1(PA1)和通道2(PA2作输入)

//////////////////////////////////////////////////////////////////
#include "adc.h"
#include "delay.h"
#include "stm32f10x_adc.h"
           
//初始化ADC
//选用的ADC1通道1,2都是规则通道
                                                                                                                                   
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和PA2 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
        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工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode = ENABLE;        //模数转换工作在扫描模式,即Scan=1
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;        //模数转换工作在连续转换模式
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = 2;        //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

        ADC_RegularChannelConfig(ADC1,ADC_Channel_1, 1,ADC_SampleTime_239Cycles5); //通道1先采样,采样时间为239.5周期        
        ADC_RegularChannelConfig(ADC1,ADC_Channel_2, 2,ADC_SampleTime_239Cycles5); //通道2在通道1后面采样;1,2是采样顺序

//使能ADC并校准
//使能ADC,复位校准,等待复位校准结束,AD校准,等待AD校准结束
        ADC_DMACmd(ADC1,ENABLE);  //使能指定的ADC的DMA请求

        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的软件转换启动功能

}




//////////////////////////////////////////////////////////
//dma.c,采用DMA1,通道1
////////////////////////////////////////////////////////

#include "dma.h"
#include "stm32f10x_dma.h"

DMA_InitTypeDef DMA_InitStructure;

//   u16 DMA1_MEM_LEN; //保存DMA每次数据传送的长度            
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/16位数据宽度/存储器增量模式
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //使能DMA1传输
        __nop();                    //等待 DMA1 时钟稳定,DMA开启需要时间稳定
          __nop();                    //经测试最少 2 个 nop
          __nop();

    DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值

//        DMA1_MEM_LEN=cndtr;
        DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取数据
        DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的大小        2
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器变化
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //外设数据宽度为16位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存数据宽度为16位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //工作在循环模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道优先
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器

        DMA_Cmd(DMA_CHx, ENABLE);  //使能DMA通道1的传输
                  
}


/////////////////////////////////////////////////////////////////////////
//main.c
////////////////////////////////////////////////////////////////////////
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "adc.h"
#include "lcd.h"
#include "usart.h"         
#include "dma.h"

u16 ADCConvertedValue[2]={0,0};

        
int main(void)
{        

        float temp;

        delay_init();                     //延时函数初始化         
        NVIC_Configuration();          //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
        uart_init(9600);                 //串口初始化为9600
         LED_Init();                             //LED端口初始化
        LCD_Init();                                  //初始化LCD
        Adc_Init();                                  //ADC初始化
                                                                                    
        //显示提示信息        
         POINT_COLOR=RED;//设置字体为红色
        LCD_ShowString(60,130,200,16,16,"ADC_CH1_VAL:");              
        LCD_ShowString(60,150,200,16,16,"ADC_CH1_VOL:0.000V");
        LCD_ShowString(60,170,200,16,16,"ADC_CH2_VAL:");              
        LCD_ShowString(60,190,200,16,16,"ADC_CH2_VOL:0.000V");

                    while(1)
                    {
                                delay_ms(250);  

                                 MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)ADCConvertedValue,2);


                                 LCD_ShowxNum(156,130,ADCConvertedValue[0],4,16,0);        //显示ADC转化的数字值
                                temp=(float)ADCConvertedValue[0]*(3.3/4096);  //转化为模拟量,3.3V的参考电压
                                ADCConvertedValue[0]=temp;         //整数部分
                                LCD_ShowxNum(156,130,ADCConvertedValue[0],1,16,0);        //显示电压的整数
                                temp-=ADCConvertedValue[0];        //模拟量减去整数部分,得到小数
                                temp*=1000;        //将小数扩大1000倍
                                LCD_ShowxNum(172,150,temp,3,16,0X80); //显示小数部分

                                LCD_ShowxNum(156,170,ADCConvertedValue[1],4,16,0);
                                temp=(float)ADCConvertedValue[1]*(3.3/4096);
                                ADCConvertedValue[1]=temp;
                                LCD_ShowxNum(156,170,ADCConvertedValue[1],1,16,0);
                                temp-=ADCConvertedValue[1];
                                temp*=1000;
                                LCD_ShowxNum(172,190,temp,3,16,0X80);

                                delay_ms(10);
                                   
                         }
}













沙发
airwill| | 2014-3-4 17:45 | 只看该作者
改程序不是内伤, 只会写代码, 不会调试的, 那才是伤呢!
现在的调试工具这么强大, 手册这么仔细, 不用怕调试哦

使用特权

评论回复
板凳
Rain_King| | 2014-3-4 17:56 | 只看该作者
调试程序时一个程序员最基本的要求.....慢慢调试吧...

使用特权

评论回复
地板
mmuuss586| | 2014-3-4 17:59 | 只看该作者
temp-=ADCConvertedValue[0];        
这有好几个地方,减之前先判断下
我猜的

使用特权

评论回复
5
ilovezeno| | 2014-3-4 17:59 | 只看该作者
你按照官方例程来改不行么。。。。

使用特权

评论回复
6
frank_1019|  楼主 | 2014-3-4 18:12 | 只看该作者
airwill 发表于 2014-3-4 17:45
改程序不是内伤, 只会写代码, 不会调试的, 那才是伤呢!
现在的调试工具这么强大, 手册这么仔细, 不用怕调试 ...

为什么我从你们的回复里面看到了偷笑的表情T^T

调试有教程吗……我不会调试……

使用特权

评论回复
7
airwill| | 2014-3-4 18:44 | 只看该作者
frank_1019 发表于 2014-3-4 18:12
为什么我从你们的回复里面看到了偷笑的表情T^T

调试有教程吗……我不会调试…… ...


心眼大一点, 不要看成是嘲笑, 就看成的鼓励和鞭策好了.
调试并没有很好的教程, 更多的是经验或者总结.
有本坛的大侠整理的调试经验, 值得推荐
https://bbs.21ic.com/icview-286228-1-1.html
不妨可下载学习一下.

使用特权

评论回复
8
frank_1019|  楼主 | 2014-3-4 19:14 | 只看该作者
airwill 发表于 2014-3-4 18:44
心眼大一点, 不要看成是嘲笑, 就看成的鼓励和鞭策好了.
调试并没有很好的教程, 更多的是经验或者总结.
有 ...

黑宝书看了,基本是教受“诊断故障的方法”,对我而言不是很适用啊,我都不知道怎么操作,有没有最基础的那种资源……

使用特权

评论回复
9
airwill| | 2014-3-4 19:18 | 只看该作者
其实就是利用好你的开发工具和开发环境, 程序执行过程和你的预期对比, 找到错误

使用特权

评论回复
10
frank_1019|  楼主 | 2014-3-4 19:46 | 只看该作者
airwill 发表于 2014-3-4 19:18
其实就是利用好你的开发工具和开发环境, 程序执行过程和你的预期对比, 找到错误 ...

请问在编译时数组是放在内存里面的?

我贴了张图在1楼,请问那个图怎么理解?我只指定义了两个元素的一维数组,怎么连续那么多地址对应的内容都是非零的?、、

还有一个问题:在debug里面能看到我相应的寄存器的配置吗?(因为用库函数操作的,不能直接看到寄存器的配置,在debug里面有这样的窗口没?)

使用特权

评论回复
11
airwill| | 2014-3-4 21:24 | 只看该作者
关于编译器, 数组放在哪里, 可以打开生成的 MAP 文件查一下数组名

使用特权

评论回复
12
tuzihog| | 2014-3-5 10:13 | 只看该作者
标注一下

使用特权

评论回复
13
shuiketu| | 2014-3-5 17:27 | 只看该作者
打断点,单步调试,一步步跟踪程序的执行,是最基本也通常是最有效的办法。

使用特权

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

本版积分规则

18

主题

66

帖子

0

粉丝