打印

波形的采集存储和回放并在液晶上画波形代码成功

[复制链接]
9387|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
     本人初学stm32,为了加深对数据采集 数据存储 ADC DAC DMA的操作!本人在2011年的电子大赛中找到了一个题《《波形的采集存储和回放》》,决定拿下它,刚开始对STM32一点都不熟练,一些简单的配置的不会,特别是在ADC采样DMA配置中吃了很多苦头,循环缓存模式和Normal模式的选择时,我第一次就选择的是循环缓存模式,我在SRAM中定义了个100个字节大小的数组,我就想确定我采集的数据是不是和原始波形的数据一样,我就把数组里的数据通过在液晶上画点画出来的,最后我发现波形很乱,我就判断我采集数据不对!为啥不对呢?配置那些都是对的呀,突然想到我用的是循环缓存模式,循环模式是在数据把数组里装满后我们还没有来得及去存储它,新来的数据又把数组上次采集的数据覆盖了,最后我换成了Normal模式采集了1200个字节的数据,在液晶上画点波形很给力,这下我的数据对了!我又开始整存储,我采取的方法是把它存在内部FLASH,用它来模拟一个EEPROM,因为我们的数据很小所以可以存在他的内部FLASH里面,我是从内部地址#define FLASH_SAVE_ADDR  0X08070000开始存储,在写入FLASH时注意他是有写保护的,在写入时对FLASH解锁,最后数据写入完成时必须给FLASH上锁!!FLASH里面的操作是很难的,向我们这些新手需要多花时间,到时候需要代码的可以找我要,我希望我在电子世界里交更多的好朋友,做技术是很寂寞的!!我采取按键的方法写入和读出,读出的数据我存在SRAM定义的一个数组中通过DMA把它发送到这个DAC数据保持寄存器 DAC_DHR12R1    地址为#define DAC_DHR12R1_Address  ((u32)0x40007408)    我还用用这个数组里面的数据在我的液晶上画了波形图,看起来还不错    最后我才去示波器的2个通道,一个监视原始波形,一个监视从FLASH的读回来的波形,周期和原来的波形的周期在误差范围类!!   我采样的是示波器上面的方波电压在0~2.5V    下面发几张图给大家看看   部分代码    要要完整的联系我的QQ:554253547    希望多认识朋友    交流技术    我下面想做个GPS,希望有人能提供技术支持!!!!!里面的那个板子是自己画的   感觉有点丑  但是是自己的处女作!!!!








#include "led.h"
#include "stmflash.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
#include "lcd.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "key.h"
#include "dac.h"
u16 ADC_ConvertedValue[600];//ADC采样回来存储的数组
//u16 ADC_ConvertedValue[50];//ADC采样回来存储的数组
//extern u8  TIM5CH1_CAPTURE_STA;                //输入捕获状态                                                   
//extern u16        TIM5CH1_CAPTURE_VAL;        //输入捕获值
u16 datatemp[600];//从芯片内部FLASH里面读回的ADC采样值
#define FLASH_SAVE_ADDR  0X08070000 //设置FLASH 保存地址(必须为偶数)

/************************************************************************
                                          
******************           MAIN函数                     ************************

************************************************************************/


int main(void)
{  
        u16  i=0;           //循环次数
        u8  key;          //扫描的按键值
        u16   adcx;          //从FLASH读出的AD采样
        float temp;           // 采集的每个点对应的电压值
        u16 x=0;          //X轴代表的是时间
        u16 y;                //Y轴上对应的电压大小
        u16 Y_VALUE;                // Y的值
        u16 X_VALUE;                // X的值
         u16 X_LAST_VALUE;        //上次X的值
         u16 Y_LAST_VALUE;        //上次Y的值
        SystemInit();
        delay_init(72);             //延时初始化
        NVIC_Configuration();
        uart_init(9600);
        LED_Init();  //LED初始化
        LCD_Init();         //液晶初始化
        Adc_Init();         //ADC初始化
        TIM5_Cap_Init(0XFFFF,71);        //以1Mhz的频率计数
        Dac1_Init();   //DAC初始化
    DMA_ADC_Config((u32)ADC_ConvertedValue);  //运输ADC采样值到SRAM的DMA
        DMA_DAC_Config((u32)datatemp);                         //运输FLASH内存储的ADC采样值到DAC的DMA


        POINT_COLOR=RED;
        LCD_ShowString(60,10,"Peter ILOVEpu");
        LCD_ShowString(60,30,"PA0_round_T:1Ms");   //显示周期             
        LCD_ShowString(60,50,"MAX_U: 2.5V");           //最大值
        LCD_ShowString(60,70,"MIN_U: 0V");                   //最小值
//         LCD_ShowString(60,70,"PA1_Round:     us");

       
        while(1)
        {       
//
/************************************************************************

******************           捕获周期函数                  ************************

************************************************************************/
//                        delay_ms(10);
//
//                 POINT_COLOR=BLUE;                 
//                 if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿
//                {
//                        temp=TIM5CH1_CAPTURE_STA&0X3F;                        //  去掉bit7和bit6  只剩下0~5位为我们所需溢出次数
//                        temp*=65536;//溢出时间总和
//                        temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间
//                        round=2*temp;
//                        LCD_ShowNum(140,70,round,4,16);//打印总的高点平时间
//                        TIM5CH1_CAPTURE_STA=0;//开启下一次捕获
//                }
////
//                        }

/************************************************************************

******************       FLASH测试函数                  ************************

************************************************************************/

                                  
//                        for(i=0;i<600;i++)
//                          {
//                                          DAC_SetChannel1Data(DAC_Align_12b_R,datatemp);  //12位右对齐数据格式设置DAC值
//                                                           key=KEY_Scan(0);
//
//                if(key==1)//KEY0按下,写入STM32 FLASH
//                {
//
//                     LED0=!LED0;
//                         //LCD_Fill(0,150,239,319,WHITE);//清除半屏
//                    delay_ms(300);  
//                        LCD_ShowString(60,190,"Start Write FLASH...");
//                        STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)ADC_ConvertedValue,600);
//                        LCD_ShowString(60,210,"FLASH Write Finished!"); //提示传送完成
//
//                }
//                if(key==2)//KEY1按下,读取FLASH内部的数据
//                {
//                         delay_ms(300);
//                         LCD_ShowString(60,70,"Start Read FLASH....");                         
//                    STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,600);
//                        LCD_ShowString(60,90,"FLASH Read Finished!"); //提示传送完成
//                //        i=0;
//                        LED1=!LED1;
//               
//
//                }       



                       
               
//                                                                 adcx=datatemp;
//                                                          LCD_ShowNum(156,30,adcx,4,16);//显示ADC的值
//                                                        temp=(float)adcx*(3.3/4096);
//                                       
//                                               
//                                                        adcx=temp;
//                                                        LCD_ShowNum(156,50,adcx,1,16);//显示电压值
//                                                        temp-=adcx;
//                                                        temp*=1000;
//                                                        LCD_ShowNum(172,50,temp,3,16);
////                                                                LED1=!LED1;
//                          }
               
/************************************************************************

******************          示波器及回放                 ************************

************************************************************************/

                                      
                                for(i=0;i<600;i++)
                                        {
                                        delay_ms(10);
                                                        POINT_COLOR=BLUE;
                                                         adcx=datatemp;
                                                                        key=KEY_Scan(0);
                       
                                        if(key==1)//KEY0按下,写入STM32 FLASH
                                        {
                       
                                             LED0=!LED0;
                                                 LCD_Fill(0,150,239,319,WHITE);//清除半屏
                                            delay_ms(500);  
                                                LCD_ShowString(60,90,"Start Write FLASH...");
                                                STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)ADC_ConvertedValue,600);
                                                LCD_ShowString(60,110,"FLASH Write Finished!"); //提示传送完成
                       
                                        }
                                        if(key==2)//KEY1按下,读取FLASH内部的数据
                                        {
                                                 delay_ms(500);
                                                 LCD_ShowString(60,90,"Start Read FLASH....");                         
                                            STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,600);
                                                LCD_ShowString(60,110,"FLASH Read Finished!"); //提示传送完成
                                                LED1=!LED1;
                                        //        i=0;
                       
                                        }

//                                                         LCD_ShowNum(156,30,adcx,4,16);//显示ADC的值
                                                        temp=(float)adcx*(3.3/4096);
                                               
                                                        Y_LAST_VALUE=Y_VALUE;                                                                                                //取上一次的y值
                                                        y=220-temp*24;                                                                //确定y的值
                                                        Y_VALUE=y;
                                               
                                                        adcx=temp;
//                                                        LCD_ShowNum(156,50,adcx,1,16);//显示电压值
                                                        temp-=adcx;
                                                        temp*=1000;
//                                                        LCD_ShowNum(172,50,temp,3,16);

                                                        POINT_COLOR=BLUE;
                                                        LCD_DrawPoint(x,y);                                         //画点
                                               
                                                         X_LAST_VALUE=X_VALUE;                                                                                                //取上一次的x值
                                                        x++;
                                                        X_VALUE=x;
                                               
                                                        if(x==240)
                                                        {
                                                                x=0;
                                                                LCD_Fill(0,150,240,320,WHITE);                        //清屏
                                                        }
                                                       
                                                        if(Y_LAST_VALUE!=0&&x!=0&&X_LAST_VALUE!=240&&X_LAST_VALUE!=0)
                                                        LCD_DrawLine(X_LAST_VALUE,Y_LAST_VALUE,x,y);                                        //画线
                                               
                                                  LED1=!LED1;       
                               
                                }       
                       

               

}

}





#include "dma.h"
#define DAC_DHR12R1_Address  ((u32)0x40007408)//DAC数据保持寄存器地址
#define ADC1_DR_Address     ((u32)0x4001244c)//ADC数据采集地址

/****************************************************************************

   DMA    ADC采样的数据转移到SRAM中的ADC_ConvertedValue[]数组中
   ADC采样转换的数据寄存器地址      ADC1_DR_Address=((u32)0x4001244c)

*****************************************************************************/
void DMA_ADC_Config(u32 cmar)
{
        DMA_InitTypeDef DMA_InitStruct;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //使能DMA传输
       
         DMA_DeInit(DMA1_Channel1);    //复位DMA1的第一通道,关闭状态设置
  DMA_InitStruct.DMA_PeripheralBaseAddr = ADC1_DR_Address;   //DMA对应的外设基地址
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //转换结果的数据大小
  DMA_InitStruct.DMA_MemoryBaseAddr = cmar;          //内存地址
  DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;   //DMA的转换模式是SRC模式,就是从外设向内存中搬运
  DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;         //M2M模式禁止,memory to memory
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  //DMA搬运的数据尺寸,注意ADC是12位的,

  //接收一次数据后,目标内存地址后移,用来采集多个数据的
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //接收一次数据后,设备地址不后移

  //转换模式:常用循环缓存模式。如果M2M开启了,则这个模式失效
  //另一种是Normal模式:不循环,仅一次DMA
  DMA_InitStruct.DMA_Mode  = DMA_Mode_Normal;

  DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA优先级,高
  DMA_InitStruct.DMA_BufferSize = 50;  //DMA缓存大小
  DMA_Init(DMA1_Channel1,&DMA_InitStruct);

  // Enable DMA1
// DMA_Cmd(DMA1_Channel1, ENABLE);
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
        DMA_Cmd(DMA1_Channel1, ENABLE);
       
}

/*********************************************************************************

    DMA    SRAM的数据转换到DAC数据保持寄存器   
        数据保持寄存器的地址为 DAC_DHR12R1_Address=0x40007408

**********************************************************************************/
  void DMA_DAC_Config(u32 cmar)
{
        DMA_InitTypeDef DMA_InitStruct;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //使能DMA传输
       
         DMA_DeInit(DMA1_Channel1);    //复位DMA1的第一通道,关闭状态设置
  DMA_InitStruct.DMA_PeripheralBaseAddr = DAC_DHR12R1_Address;   //DMA对应的外设基地址
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //转换结果的数据大小
  DMA_InitStruct.DMA_MemoryBaseAddr = cmar;          //内存地址
  DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;   //DMA的转换模式是DST模式,就是从内存向外设中搬运
  DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;         //M2M模式禁止,memory to memory
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  //DMA搬运的数据尺寸,注意DAC是12位的,

  //发送一次数据后,目标内存地址后移,用来发送多个数据的
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //接收一次数据后,设备地址不后移

  //转换模式:常用循环缓存模式。如果M2M开启了,则这个模式失效
  //另一种是Normal模式:不循环,仅一次DMA
  DMA_InitStruct.DMA_Mode  = DMA_Mode_Circular;

  DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA优先级,高
  DMA_InitStruct.DMA_BufferSize = 600;  //DMA缓存大小
  DMA_Init(DMA1_Channel1,&DMA_InitStruct);

  // Enable DMA1

        DMA_Cmd(DMA1_Channel1, ENABLE);
       
}





#include "dac.h"

/*********************************************************************************

  DAC通道1输出初始化
                                                                          
**********************************************************************************/

void Dac1_Init(void)
{

        GPIO_InitTypeDef GPIO_InitStructure;
        DAC_InitTypeDef DAC_InitType;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );          //使能PORTA通道时钟
           RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );          //使能DAC通道时钟

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                 // 端口配置
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                  //模拟输入
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_SetBits(GPIOA,GPIO_Pin_4);//PA.4 输出高
                                       
        DAC_InitType.DAC_Trigger=DAC_Trigger_None;        //不使用触发功能 TEN1=0
        DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
        DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
        DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;        //DAC1输出缓存关闭 BOFF1=1
    DAC_Init(DAC_Channel_1,&DAC_InitType);         //初始化DAC通道1

        DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1

    DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值

}

//设置通道1输出电压
//vol:0~3300,代表0~3.3V
void Dac1_Set_Vol(u16 vol)
{
        float temp=vol;
        temp/=1000;
        temp=temp*4096/3.3;
        DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
}







#include "adc.h"

                  
//初始化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);   //72M/6=12,ADC最大时间不能超过14M
        //PA0/1/2/3 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//|GPIO_Pin_1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);       

        ADC_DeInit(ADC1);  //将外设 ADC1 的全部寄存器重设为缺省值
                       
                          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 = 1; //进行规则转换的ADC通道的数目
                          ADC_Init(ADC1, &ADC_InitStructure);   //初始化各个寄存器
                       
                          /* ADC1 regular channel_8 configuration */
                          ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);        //PA0的采样的240周期
                //          ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5);        //PA1的采样的240周期
                          // ADC1 to DMA, Enable
               
                                ADC_DMACmd(ADC1, ENABLE); //ADC命令,和DMA关联
                          /* Enable ADC1 */
                           ADC_Cmd(ADC1, ENABLE);         //使能指定的ADC1   ADC_CR2_ADON[0]=1;  打开A/D转换器
                       
                          /* Enable ADC1 reset calibaration register */   
                          ADC_ResetCalibration(ADC1);        //重置指定的ADC1的校准寄存器        ADC1_CR2[3]=1;
                          /* Check the end of ADC1 reset calibration register */
                          while(ADC_GetResetCalibrationStatus(ADC1));  ////获取ADC1重置校准寄存器的状态,设置状态则等待
                       
                          /* Start ADC1 calibaration */
                          ADC_StartCalibration(ADC1);                        //开始指定ADC1的校准状态   ADC1_CR2[2]=1;
                          /* Check the end of ADC1 calibration */
                          while(ADC_GetCalibrationStatus(ADC1));           //获取指定ADC1的校准程序,设置状态则等待
                             
                          /* Start ADC1 Software Conversion */


}                                  


























































相关帖子

沙发
qqcaiyin| | 2013-6-20 23:27 | 只看该作者
咱  最近也在学习这方面的

使用特权

评论回复
板凳
554253547|  楼主 | 2013-6-21 00:13 | 只看该作者
qqcaiyin 发表于 2013-6-20 23:27
咱  最近也在学习这方面的

呵呵  代码写完没有

使用特权

评论回复
地板
qqcaiyin| | 2013-6-21 08:09 | 只看该作者
554253547 发表于 2013-6-21 00:13
呵呵  代码写完没有

还没动身,nand flash ,液晶还在学,
直接附件上传啊,供大家学习

使用特权

评论回复
5
554253547|  楼主 | 2013-6-21 12:07 | 只看该作者
直接给个地址去下嘛   http://pan.baidu.com/share/home?uk=2972336019

使用特权

评论回复
6
pl870710862| | 2013-6-21 21:46 | 只看该作者
晕,原来你也在这……我就说看着怎么那么眼熟!

使用特权

评论回复
7
dqyubsh| | 2013-6-21 23:33 | 只看该作者
直接上传到主机,这种应用更常见。

使用特权

评论回复
8
554253547|  楼主 | 2013-6-22 00:32 | 只看该作者
dqyubsh 发表于 2013-6-21 23:33
直接上传到主机,这种应用更常见。

??????? 上传主机

使用特权

评论回复
9
wangkangming| | 2013-6-22 20:02 | 只看该作者
LZ牛人,佩服!   

使用特权

评论回复
10
wuzx-61| | 2013-6-22 21:32 | 只看该作者
顶楼主!

使用特权

评论回复
11
554253547|  楼主 | 2013-6-23 10:37 | 只看该作者
wangkangming 发表于 2013-6-22 20:02
LZ牛人,佩服!

谈不上  刚上M3还没有三个月  还要继续加油  希望能与更多的人进行技术交流  

使用特权

评论回复
12
sinc_mark| | 2013-6-24 09:57 | 只看该作者
兴趣是最好的导师,祝LZ能在这里广交朋友!

使用特权

评论回复
13
554253547|  楼主 | 2013-6-25 13:45 | 只看该作者
sinc_mark 发表于 2013-6-24 09:57
兴趣是最好的导师,祝LZ能在这里广交朋友!

    现在越来越对这方便有兴趣了 等这几个月把硬件调通了  就去去整嵌入式

使用特权

评论回复
14
mcu61| | 2013-6-25 14:27 | 只看该作者
很喜欢lz的示波器。
个人买的,还是公司的呢?

使用特权

评论回复
15
liusensen| | 2013-6-25 15:33 | 只看该作者
兴趣是最好的老师 !

使用特权

评论回复
16
554253547|  楼主 | 2013-6-25 15:54 | 只看该作者
liusensen 发表于 2013-6-25 15:33
兴趣是最好的老师 !

就是

使用特权

评论回复
17
554253547|  楼主 | 2013-6-30 12:46 | 只看该作者
mcu61 发表于 2013-6-25 14:27
很喜欢lz的示波器。
个人买的,还是公司的呢?

学校的    很贵的   十万块呢     能达到500M的采样

使用特权

评论回复
18
1181607687| | 2013-7-1 09:00 | 只看该作者
有点启发···多谢楼主

使用特权

评论回复
19
554253547|  楼主 | 2013-7-1 23:17 | 只看该作者
1181607687 发表于 2013-7-1 09:00
有点启发···多谢楼主

  呵呵 没事小意思   技术就是要相互交流   

使用特权

评论回复
20
554253547|  楼主 | 2013-7-15 14:50 | 只看该作者
.......

使用特权

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

本版积分规则

4

主题

38

帖子

1

粉丝