搜索
bottom↓
回复: 0

全功能智能车之CCD ADC 触发DMA传输(第十四篇)

[复制链接]

出0入0汤圆

发表于 2018-5-12 12:14:13 | 显示全部楼层 |阅读模式
这篇主要讲CCD ADC 触发DMA传输,这算是完善一点原本的CCD等待ADC传输完成的功能,更加的提高了效率,这个最大的意义不在于此,而是在于以后的用定时器触发ADC,到那时就能够实现   定时器->ADC->DMA  最后就只要去处理DMA完成的那个数据就行
具体代码如下:
首先是主函数:
  int main(void){        u16 i,cnt;  Stm32_Clock_Init(9);    //系统时钟设置    uart_init(72,115200);         //串口初始化为115200    delay_init(72);                //延时初始化    LED_Init();                  //初始化与LED连接的硬件接口     LCD_Init();                   //初始化LCD    usmart_dev.init(72);    //初始化USMART                //    TIM3_Int_Init(exposureTime-1,71);   //初始化定时器  用来采样CCD    MYDMA_Config(DMA1_Channel1,(u32)Pixel);  //初始化DMA1通道        CCD_init();          //初始化CCD    //初始化数据  for(i=0; i<CCD_LENGTH; i++) {    Pixel=0;  }    POINT_COLOR=RED;//设置字体为红色    LCD_ShowString(60,10,200,16,16,"CCD TEST");        LCD_ShowString(60,30,200,16,16,"Maid:piaoran");        LCD_ShowString(60,50,200,16,16,"Date:2015-11-28");          LCD_ShowString(20,70,200,16,16,"ccd_max:0000  ccd_min:0000");          LCD_ShowString(20,90,200,16,16,"exp_tim:0000  ccd_avg:0000");    //VerifyExposure();    while(1)    {        ImageCapture(Pixel);        if(++cnt >= 5) {            cnt = 0;            SendImageData(Pixel);        }        //LCD_Put32REG(0,130,"DMA->CNDTR:",DMA1_Channel1->CNDTR);        LED0=!LED0;        delay_ms(500);        }}

这里调用了DMA初始化函数:
//DMA1的各通道配置//这里的传输形式是固定的,这点要根据不同的情况来修改//从存储器->外设模式/8位数据宽度/存储器增量模式//DMA_CHx:DMA通道CHx          DMA_CHx即DMA通道,跟由什么触发DMA采样有关//cpar:外设地址//cmar:存储器地址                                                                                                                                                                        //外部中断触发定时器,定时器发出请求使DMA进行数据传输//cndtr:数据传输量                                                                                                                                                                 //用一个外部中断触发,触发DMA进行数据传输void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cmar){        DMA_InitTypeDef DMA_InitStructure;        NVIC_InitTypeDef NVIC_InitStructure;         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //使能DMA传输  DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值        DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC1->DR;  //DMA外设数据寄存器的基地址        从ADC里获得数据        DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址                        数组的基地址        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取到DMA        DMA_InitStructure.DMA_BufferSize = CCD_LENGTH ;  //DMA通道的DMA缓存的大小,可以理解为DMA传输次数         // 最大传输数量为2^16-1=65535  总共需要153600个字节。貌似超过了   所以一次采320*2 一行 ,采240次        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //外设数据宽度为8位  即一个字节        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA数据宽度为8位        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式                                        工作在单次模式,即只传输完一个流程        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 x拥有中优先级         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输        DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器                NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;  //DMA通道1中断        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //先占优先级0级        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //从优先级3级        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能        NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器                         DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);}
这里只是初始化,而使能在CCD采集函数中:/**************************************************************************  函数名称:ImageCapture*  功能说明:CCD采样程序*  参数说明:* ImageData   采样数组*  函数返回:无*  修改时间:2015-11-28×  作者: 蓝宙电子工作室 ×  修改:piaoran  QQ:384710930*  备    注:ImageCapture(Pixel);*************************************************************************/void ImageCapture(unsigned short * ImageData) {    unsigned char i;                MYDMA_Enable(DMA1_Channel1);  //使能TM3 TX DMA1 所指示的通道                 DMA1->IFCR =0XFFFFFFFF;    CCD_SI=1;               SamplingDelay();    CCD_CLK=1;             SamplingDelay();    CCD_SI=0;    SamplingDelay();                Adc_auto();    CCD_CLK=0;              for(i=0; i<127; i++) {        SamplingDelay();        CCD_CLK=1;              SamplingDelay();                                Adc_auto();        CCD_CLK=0;        }    SamplingDelay();    CCD_CLK=1;             SamplingDelay();    CCD_CLK=0;         }
其中的使能函数如下,注意这里要在失能的情况下才能够在赋值字节数:
//开启一次DMA传输void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx){         DMA_Cmd(DMA_CHx, DISABLE );  //关闭DMA_CHx DMA1 所指示的通道               DMA_SetCurrDataCounter(DMA_CHx,CCD_LENGTH);//DMA通道的DMA缓存的大小         DMA_Cmd(DMA_CHx, ENABLE);  //使能DMA通道}
那DMA传输完成128个半字后将进入DMA传输完成中断,代码如下://DMA传输完成中断函数void DMA1_Channel1_IRQHandler(void){        DMA_ClearITPendingBit(DMA1_IT_GL1);        LED1=!LED1;        MYDMA_Enable(DMA1_Channel1);}还有一个代码片段就是ADC的初始化函数,这里使能了ADC的DMA功能:
//初始化ADC//这里我们仅以规则通道为例//我们默认仅开启通道1                                                                                                                                           void  Adc_Init(void){            //先初始化IO口         RCC->APB2ENR|=1<<2;    //使能PORTA口时钟         GPIOA->CRL&=0XFFFFFF0F;//PA1 anolog输入        //通道10/11设置                                 RCC->APB2ENR|=1<<9;    //ADC1时钟使能                  RCC->APB2RSTR|=1<<9;   //ADC1复位        RCC->APB2RSTR&=~(1<<9);//复位结束                    RCC->CFGR&=~(3<<14);   //分频因子清零                //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!        //否则将导致ADC准确度下降!         RCC->CFGR|=2<<14;                       ADC1->CR1&=0XF0FFFF;   //工作模式清零        ADC1->CR1|=0<<16;      //独立工作模式          ADC1->CR1&=~(1<<8);    //非扫描模式                  ADC1->CR2&=~(1<<1);    //单次转换模式        ADC1->CR2&=~(7<<17);                   ADC1->CR2|=7<<17;           //软件控制转换          ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!!        必须使用一个事件来触发        ADC1->CR2&=~(1<<11);   //右对齐                 //设置转换序列 设置CCD的通道        ADC1->SQR3&=0XFFFFFFE0;     //规则序列1 通道ch        ADC1->SQR3|=CCD_Channel;                 //设置CCD的通道        //设置通道1的采样时间        ADC1->SMPR2&=~(7<<3);  //通道1采样时间清空                   ADC1->SMPR2|=7<<3;     //通道1  239.5周期,提高采样时间可以提高精确度                 ADC1->CR2|=1<<8;       //使能ADC的DMA         ADC1->CR2|=1<<0;           //开启AD转换器                 ADC1->CR2|=1<<3;       //使能复位校准          while(ADC1->CR2&1<<3); //等待校准结束                            //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。                          ADC1->CR2|=1<<2;        //开启AD校准                   while(ADC1->CR2&1<<2);  //等待校准结束        //该位由软件设置以开始校准,并在校准结束时由硬件清除  }
还有就是触发ADC的函数,代码如下:
void Adc_auto(void)   {                                     ADC1->CR2|=1<<22;       //启动规则转换通道 }
至此CCD的ADC触发DMA的功能就此完成,下一步要做的将是定时器触发ADC传输,这样之后CCD采集函数将全部由中断函数来完成。
现在来看看实验效果:



源代码下载地址:
http://download.csdn.net/detail/chengdong1314/9310431


阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-28 20:01

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表