554253547 发表于 2013-6-20 22:39

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

   本人初学stm32,为了加深对数据采集 数据存储 ADC DAC DMA的操作!本人在2011年的电子大赛中找到了一个题《《波形的采集存储和回放》》,决定拿下它,刚开始对STM32一点都不熟练,一些简单的配置的不会,特别是在ADC采样DMA配置中吃了很多苦头,循环缓存模式和Normal模式的选择时,我第一次就选择的是循环缓存模式,我在SRAM中定义了个100个字节大小的数组,我就想确定我采集的数据是不是和原始波形的数据一样,我就把数组里的数据通过在液晶上画点画出来的,最后我发现波形很乱,我就判断我采集数据不对!为啥不对呢?配置那些都是对的呀,突然想到我用的是循环缓存模式,循环模式是在数据把数组里装满后我们还没有来得及去存储它,新来的数据又把数组上次采集的数据覆盖了,最后我换成了Normal模式采集了1200个字节的数据,在液晶上画点波形很给力,这下我的数据对了!我又开始整存储,我采取的方法是把它存在内部FLASH,用它来模拟一个EEPROM,因为我们的数据很小所以可以存在他的内部FLASH里面,我是从内部地址#define FLASH_SAVE_ADDR0X08070000开始存储,在写入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;//ADC采样回来存储的数组
//u16 ADC_ConvertedValue;//ADC采样回来存储的数组
//extern u8TIM5CH1_CAPTURE_STA;                //输入捕获状态                                                 
//extern u16        TIM5CH1_CAPTURE_VAL;        //输入捕获值
u16 datatemp;//从芯片内部FLASH里面读回的ADC采样值
#define FLASH_SAVE_ADDR0X08070000 //设置FLASH 保存地址(必须为偶数)

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

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


int main(void)
{
        u16i=0;           //循环次数
        u8key;          //扫描的按键值
        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                                                                                                                                          
voidAdc_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=1;打开A/D转换器
                       
                          /* Enable ADC1 reset calibaration register */   
                          ADC_ResetCalibration(ADC1);        //重置指定的ADC1的校准寄存器        ADC1_CR2=1;
                          /* Check the end of ADC1 reset calibration register */
                          while(ADC_GetResetCalibrationStatus(ADC1));////获取ADC1重置校准寄存器的状态,设置状态则等待
                       
                          /* Start ADC1 calibaration */
                          ADC_StartCalibration(ADC1);                        //开始指定ADC1的校准状态   ADC1_CR2=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 static/image/common/back.gif
咱最近也在学习这方面的

呵呵代码写完没有

qqcaiyin 发表于 2013-6-21 08:09

554253547 发表于 2013-6-21 00:13 static/image/common/back.gif
呵呵代码写完没有

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

554253547 发表于 2013-6-21 12:07

直接给个地址去下嘛   http://pan.baidu.com/share/home?uk=2972336019

pl870710862 发表于 2013-6-21 21:46

晕,原来你也在这……我就说看着怎么那么眼熟!

dqyubsh 发表于 2013-6-21 23:33

直接上传到主机,这种应用更常见。

554253547 发表于 2013-6-22 00:32

dqyubsh 发表于 2013-6-21 23:33 static/image/common/back.gif
直接上传到主机,这种应用更常见。

??????? 上传主机

wangkangming 发表于 2013-6-22 20:02

LZ牛人,佩服!   

wuzx-61 发表于 2013-6-22 21:32

顶楼主!

554253547 发表于 2013-6-23 10:37

wangkangming 发表于 2013-6-22 20:02 static/image/common/back.gif
LZ牛人,佩服!

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

sinc_mark 发表于 2013-6-24 09:57

兴趣是最好的导师,祝LZ能在这里广交朋友!

554253547 发表于 2013-6-25 13:45

sinc_mark 发表于 2013-6-24 09:57 static/image/common/back.gif
兴趣是最好的导师,祝LZ能在这里广交朋友!

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

mcu61 发表于 2013-6-25 14:27

很喜欢lz的示波器。
个人买的,还是公司的呢?

liusensen 发表于 2013-6-25 15:33

兴趣是最好的老师 !

554253547 发表于 2013-6-25 15:54

liusensen 发表于 2013-6-25 15:33 static/image/common/back.gif
兴趣是最好的老师 !

就是

554253547 发表于 2013-6-30 12:46

mcu61 发表于 2013-6-25 14:27 static/image/common/back.gif
很喜欢lz的示波器。
个人买的,还是公司的呢?

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

1181607687 发表于 2013-7-1 09:00

有点启发···多谢楼主

554253547 发表于 2013-7-1 23:17

1181607687 发表于 2013-7-1 09:00 static/image/common/back.gif
有点启发···多谢楼主

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

554253547 发表于 2013-7-15 14:50

.......
页: [1] 2
查看完整版本: 波形的采集存储和回放并在液晶上画波形代码成功