STM32测试程序 ADC+DMA+串口发送。全代码奉献(操作寄存器)

2019-07-21 07:55发布

在参考网站上的例子(那个例子定义的数组为U8,这个很头痛)和自己的努力终于完成了ADC+DMA+串口发送的测试程序。这个在我的项目的用到的。现在和大家分享我的成果。其实这个论坛上也有这样的例子,只是都是不全的,也没有很强的针对性。不过他们已经完成了一些参数的设计,所以值得参考,我自己的程序是针对ADC+DMA+串口发送而设计,对初学者来说会很有帮助。本程序在ALIENTEK MiniSTM32开发板上验证。参考本论坛的资料

#include "stm32f10x_lib.h"
#include "sys.h"
#include "delay.h"
#define USART1_DR_Base  0x40013804 
#define ADC1_DR_Address 0x4001244C //0x40012400+0x4C
//#define DMA1_MEM_ADD    (u32)ADC_Buf
//#define DMA1_MEM_SIZE    (u32)sizeof(ADC_Buf)
u16 ADC_Buf[512];
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx);//配置DMA1_CHx
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);//使能DMA1_CHx
void MYDMA_GOnes(DMA_Channel_TypeDef*DMA_CHx); //执行一次DMA   
void  adc_init(void) ;
void  USART_Initaize(u32 pclk2,u32 bound);
void  Uart1_PutChar(u8 ch);
void Uart1_PutString(u8 *Buf, u8 Len);
//主函数的内容:
int main(void)
{    
 u16 times=0;
 u16 t;
 u32 temp =0;
 u16 adcx;
 u8 table[5];
 u8 *p;
 p= table;
 Stm32_Clock_Init(9);//88M
 delay_init(72);     //延时初始化
 USART_Initaize(72,9600); //设置波特率
 adc_init();
   while (1)
    {
     if(DMA1->ISR&(1<<1)) //传输完成了
  { 
   times++;    
   for(t=0;t<5;t++)
   {   
    temp = temp + ADC_Buf[t];
   }
   temp = temp /5;
   adcx=temp*330/4096;;    
   table[0]=adcx / 100 + 0x30;
   table[1]='.';
   table[2]=adcx % 100/10 + 0x30;
   table[3]= adcx %10 + 0x30;
   table[4]='V';
   Uart1_PutString(p,5);
   Uart1_PutString(" ",2);
   temp =0;
   DMA1->IFCR|=1<<1;
   MYDMA_GOnes(DMA1_Channel1);
  }
                  
    } 
              
 } 
   
void  adc_init(void)
{    
 RCC->APB2ENR|=1<<2;    //使能PORTA口时钟 
 GPIOA->CRL&=0XFFFFFFF0;//PA.0 anolog输入 
 //通道10/11设置  
 RCC->APB2ENR|=1<<9;    //ADC1时钟使能
 __nop();
 __nop();     
 RCC->APB2RSTR|=1<<9;   //ADC1复位
 RCC->APB2RSTR&=~(1<<9);//复位结束  
 RCC->CFGR|=3<<14;      //SYSCLK/DIV2=88M/8=11Mhz 得到ADC采样率位43.65Khz   
 
 ADC1->CR1&=0XF0FFFF;   //独立工作模式
 ADC1->CR1|=1<<8;       //扫描模式   
 ADC1->CR2|=1<<1;       //连续转换模式 
 ADC1->CR2|=0x000E0000; //软件控制转换 由bit21控制
 ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!! 必须使用一个事件来触发
 ADC1->CR2&=~(1<<11);   //右对齐
 ADC1->SQR1&=0xFFF0FFFF;//1个转换在规则序列中  
 ADC1->SQR3&=0XFFFFFFE0;//规则序列1=通道0
 ADC1->SQR3|=0;    
 ADC1->SMPR2|=0X07;     //通道0的转换时间为:239.5+12.5个ADC时钟周期    
 ADC1->CR2|=1<<0;       //开启AD转换器,第一次唤醒AD转换器  
 ADC1->CR2|=1<<3;       //使能复位校准  
 while(ADC1->CR2&1<<3); //等待校准结束   
    //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。    
 ADC1->CR2|=1<<2;       //开启AD校准    
 while(ADC1->CR2&1<<2); //等待校准结束
 //该位由软件设置以开始校准,并在校准结束时由硬件清除    
 ADC1->CR2|=1<<8;    //开启ADC DMA转换
 MYDMA_Config(DMA1_Channel1);//配置DMA通道1
 MYDMA_Enable(DMA1_Channel1);//开启DMA通道1 
 ADC1->CR2|=1<<0;    //开启AD转换   
}
//获得ADC值
u16 get_adc(void)   
{     
 ADC1->CR2|=1<<22;       //启动规则转换通道 
 while(!(ADC1->SR&1<<1));//等待转换结束      
 return ADC1->DR; //返回adc值         
}
//DMA1的各通道配置
//DMA_CHxMA1的通道 参考手册
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx)
{
 RCC->AHBENR|=1<<0;//开启DMA1时钟
 __nop();                    //等待 DMA1 时钟稳定
    __nop();                    //经测试最少 2 个 nop
    __nop();
 DMA_CHx->CPAR=ADC1_DR_Address;//DMA1 外设地址 ADC1_DR_Address
 DMA_CHx->CMAR=(u32)ADC_Buf ;   //DMA1,ADC 存储器地址
 DMA_CHx->CNDTR=(u32)sizeof(ADC_Buf) ;  //DMA1,传输数据量
 DMA_CHx->CCR=0X00000000;//复位
 DMA_CHx->CCR|=0<<4;  //从外设器件读数据
 DMA_CHx->CCR|=0<<5;  //非循环模式
 DMA_CHx->CCR|=0<<6;  //外设地址非增量模式
 DMA_CHx->CCR|=1<<7;  //存储器增量模式
 DMA_CHx->CCR|=1<<8;  //外设数据宽度为16位
 DMA_CHx->CCR|=1<<10; //存储器数据宽度16位
 DMA_CHx->CCR|=1<<13; //高优先级
 DMA_CHx->CCR|=0<<14; //非存储器到存储器模式   
}
//开启 DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
 DMA_CHx->CCR|=1<<0;  //开启DMA传输
}   
//开启一次DMA传输
//单次DMA转换之后,必须把DMA关闭,再次启动,才能实现第二次DMA传输!!!
void MYDMA_GOnes(DMA_Channel_TypeDef*DMA_CHx)
{   
 DMA_CHx->CCR&=~(1<<0);  //关闭DMA传输
 DMA_CHx->CNDTR=(u32)sizeof(ADC_Buf) ;  //DMA1,传输数据量
 DMA_CHx->CCR|=1<<0;  //开启DMA传输
}
void  USART_Initaize(u32 pclk2,u32 bound)
{
 float temp;
 u16 mantissa;
 u16 fraction;   
 temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
 mantissa=temp;     //得到整数部分
 fraction=(temp-mantissa)*16; //得到小数部分 
    mantissa<<=4;
 mantissa+=fraction;
 RCC->APB2ENR|=1<<2;   //使能PORTA口时钟 
 RCC->APB2ENR|=1<<14;  //使能串口时钟
 GPIOA->CRH&=0XFFFFF00F;
 GPIOA->CRH|=0X000008B0;//IO状态设置
   
 RCC->APB2RSTR|=1<<14;   //复位串口1
 RCC->APB2RSTR&=~(1<<14);//停止复位       
 //波特率设置
  USART1->BRR=mantissa; // 波特率设置 
 USART1->CR1|=0X200C;  //1位停止,无校验位.
#ifdef EN_USART1_RX    //如果使能了接收
 //使能接收中断
 USART1->CR1|=1<<8;    //PE中断使能
 USART1->CR1|=1<<5;    //接收缓冲区非空中断使能      
 MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级
#endif
}
void  Uart1_PutChar(u8 ch)

 USART1->DR = (u8) ch; 
 while((USART1->SR&0X40)==0);//循环发送,直到发送完毕    
}
void Uart1_PutString(u8 *Buf, u8 Len)
{
 u8 i;
 for(i= 0; i<Len; i++)
 {
  Uart1_PutChar(*Buf++);
 }
}
   
 


 
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
48条回答
正点原子
1楼-- · 2019-07-25 16:33
回复【21楼】冰是睡着的水:
---------------------------------
回复【22楼】正点原子:
---------------------------------
for(t=0;t<5;t++)
   {   
    temp = temp + ADC_Buf[t];
   }
采集5次是怎么看的呢?
难道是DMA_CHx->CNDTR=(u32)sizeof(ADC_Buf) ;  //DMA1,传输数据量 ?
那怎么计算的呢?谢谢原子哥,无意中看见这帖子,就研究了下

tian123chi
2楼-- · 2019-07-25 20:19
谢谢分享!
LEN_STM32
3楼-- · 2019-07-26 00:00
我刚好需要这个,收下了作参考!太感谢楼主了!!
iyzyh
4楼-- · 2019-07-26 04:41
 精彩回答 2  元偷偷看……
迷糊789
5楼-- · 2019-07-26 09:20
学习中!
神通广大
6楼-- · 2019-07-26 12:37
收藏

一周热门 更多>