CH559L单片机DMA方式在手工选择通道模式下AD采样数据串口输出
Posted perseverance52
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CH559L单片机DMA方式在手工选择通道模式下AD采样数据串口输出相关的知识,希望对你有一定的参考价值。
【CH559L单片机】DMA方式在手工选择通道模式下AD采样数据串口输出
- 📌相关篇《CH559L单片机ADC介绍以及ADC采样案例》
✨本篇属于上一篇背景下的细分篇。
- ADC数据串口打印:
👉通过一个10K可调定位器,连接到P11端口,一端接3.3V一端接GND.
🧾有人会有疑惑,前面都实现了USB CDC虚拟串口信息输出,为什么还要占用一个串口来作为调试数据信息的输出,这不仅浪费了硬件资源,也将调试配置增添了成本。其实尝试了将其整合到一块,调试时,发现在通过DMA方式ADC采用时打印不出数据。时有时无,整得令人无语,后面看了一下USB CDC相关的驱动代码好像也用到了DMA资源,可能是这个方面的原因导致在使用USB CDC虚拟串口输出 ADC数据时有时无的情况。
🌿DMA ADC采样方式:手工选择通道模式
和 自动交替通道模式
在官方给出的参考案例当中,已经给出了
自动交替通道模式
下的使用案例,这里就不在表述了,注意在使用官方案例的时,在串口打印的数据问题,这里也不在表述了,具体细节问题请看前面那篇文章。
🍃手工选择通道模式代码
- 📌案例来源WCH官网地址:
https://www.wch.cn/products/CH559.html
- 从
ADCAutoDMA.C
修改而来。
ADC_CTRL &= ~bADC_CHANN_MOD0; // 手工选择通道
//ADC采样有8个通道,在P1口,通道n 分别ADC_CHANN对应 (0x01 << n) ,如通道0是0x01,通道1是0x02依次类推
ADC_CHANN =0x01 << 1;//手工指定通道1
//ADC_CHANN = 0x02; //同上
- 📢采用数据说明:
📗每次采样6次,抛弃第一次和最后一次采样的数据,将第2次到第5次的数据求和,再取平均值。数据没有像官方案例那样存进Xdata区。
- 🎈ADC采样引脚
P11
/********************************** (C) COPYRIGHT *******************************
* File Name : ADCAutoDMA.C
* Author : WCH
* Version : V1.3
* Date : 2016/6/24
* Description : CH559的ADC自动DMA方式采样操作,手工选择通道模式,采样位数设置为11位 ,采样引脚P11
*******************************************************************************/
#include "..\\DEBUG.C" //调试信息打印
#include "..\\DEBUG.H"
#include <string.h>
#define ADCCount 6
UINT16X ADCbuf[ ADCCount ];// _at_ 0x0040 ; //存储ADC采样数据
UINT8 Flag;
#pragma NOAREGS
/*******************************************************************************
* Function Name : InitADCInterrupt()
* Description : ADC中断初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void InitADCInterrupt()
// ADC_SETUP |= bADC_IE_FIFO_OV; //使能FIFO溢出中断
// ADC_SETUP |= bADC_IE_AIN7_LOW; //使能AIN7低电平中断
// ADC_SETUP |= bADC_IE_ACT; //ADC完成中断
IE_ADC = 1; //使能ADC中断
/*******************************************************************************
* Function Name : InitADCAuto()
* Description : ADC自动采样初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void InitADCAuto()
P1_IE = 0x00; //关闭P1口其他数据功能,如果只用部分通道,可根据需要设定,否则影响IO正常使用
ADC_SETUP |= bADC_POWER_EN; //ADC电源使能
ADC_CK_SE |= (MASK_ADC_CK_SE & 0x0C); //设置12分频
ADC_CTRL &= ~MASK_ADC_CYCLE;
ADC_CTRL |= 0x0C;//设置ADC自动采样周期
ADC_CTRL &= ~bADC_CHANN_MOD1; //1101 1111
// ADC_CTRL |= bADC_CHANN_MOD0; //0001 0000自动通道选择通道0和通道1
ADC_CTRL &= ~bADC_CHANN_MOD0; // 手工选择通道
//ADC采样有8个通道,在P1口,通道n 分别ADC_CHANN对应 (0x01 << n) ,如通道0是0x01,通道1是0x02依次类推
ADC_CHANN =0x01 << 1;//手工指定通道1
// ADC_CHANN = 0x02;//手工指定通道1
ADC_EX_SW |= bADC_RESOLUTION;//采样位数11bit:2048
// ADC_EX_SW &= ~bADC_RESOLUTION; //采样位数10bit:1024
mDelayuS(100); //确保ADC正常启动
/*******************************************************************************
* Function Name : InitADCDMA(UINT16 addr,UINT8 num)
* Description : ADC的DMA初始化
* Input : UINT16 addr,DMA起始地址
UINT8 num,DMA剩余计数
* Output : None
* Return : None
*******************************************************************************/
void InitADCDMA( )
ADC_DMA = ADCbuf; //设置DMA起始地址
ADC_DMA_CN = ADCCount; //设置DMA剩余计数
ADC_SETUP |= bADC_DMA_EN;//使能DMA和中断
/*******************************************************************************
* Function Name : ADCInterrupt(void)
* Description : ADC 中断服务程序
*******************************************************************************/
void ADCInterrupt( void ) interrupt INT_NO_ADC using 1 //ADC中断服务程序,使用寄存器组1
printf("%02X ",(UINT16)ADC_STAT); //DC 11011100 f8 11111000
if(ADC_STAT & bADC_IF_DMA_END) //DMA完成中断
Flag = 1;
ADC_STAT |= bADC_IF_DMA_END; //清中断
printf("DMA完成中断 \\n");
if(ADC_STAT & bADC_IF_FIFO_OV) //ADC的FIFO溢出中断
ADC_STAT |= bADC_IF_FIFO_OV; //清中断
if(ADC_STAT & bADC_IF_AIN7_LOW) //AIN7低电平中断
ADC_STAT |= bADC_IF_AIN7_LOW;//清中断
if(ADC_STAT & bADC_IF_ACT) //ADC完成中断
ADC_STAT |= bADC_IF_ACT; //清中断
printf("ADC完成中断 \\n");
void main( )
UINT8 i;
UINT32X total=0;
mDelaymS(30);//上电延时,等待内部晶振稳定,必加
CfgFsys( );//CH559时钟选择配置
mInitSTDIO( );//串口0,可以用于调试
printf("start ...\\n");
Flag = 0;
//ADC采样有8个通道,在P1口,通道n 分别ADC_CHANN对应 (0x01 << n) ,如通道0是0x01,通道1是0x02依次类推
InitADCInterrupt(); //ADC自动采样初始化
InitADCAuto();//ADC中断初始化
InitADCDMA();
EA = 1;//开启全局中断
while(1)
if(Flag)
ADC_SETUP &= ~bADC_DMA_EN;//关闭DMA和中断
for( i=1;i<5;i++)
printf("%hu ",ADCbuf[i]);//初次和最后一次采样值建议丢弃
total +=ADCbuf[i];
total =total/4;
printf("ADC_value=:%lu \\n",total);//初次和最后一次采样值建议丢弃
// memset(ADCbuf, 0, sizeof(ADCbuf));//清空数组
total=0;
Flag = 0;
ADC_DMA = ADCbuf; //设置DMA起始地址
ADC_DMA_CN=ADCCount;
ADC_SETUP |= bADC_DMA_EN;//使能DMA和中断
// InitADCDMA( );
mDelaymS(1000);
时钟配置函数: CfgFsys( );//CH559时钟选择配置
我这里采用的是外部时钟源,根据自己的开发板自行选择。这里的代码是在官方的代码基础上调整过的。
/*******************************************************************************
* Function Name : CfgFsys( )
* Description : CH559时钟选择和配置函数,默认使用内部晶振12MHz,如果定义了FREQ_SYS可以
根据PLL_CFG和CLOCK_CFG配置得到,公式如下:
Fsys = (Fosc * ( PLL_CFG & MASK_PLL_MULT ))/(CLOCK_CFG & MASK_SYS_CK_DIV);
具体时钟需要自己配置
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CfgFsys( )
#if OSC_EN_XT
SAFE_MOD = 0x55; //开启安全模式
SAFE_MOD = 0xAA;
CLOCK_CFG |= bOSC_EN_XT; //使能外部晶振
mDelaymS(10);
SAFE_MOD = 0x55; //开启安全模式
SAFE_MOD = 0xAA;
CLOCK_CFG &= ~bOSC_EN_INT;
SAFE_MOD = 0x00;
#else
SAFE_MOD = 0x55; //开启安全模式
SAFE_MOD = 0xAA;
CLOCK_CFG &= ~MASK_SYS_CK_DIV;
// CLOCK_CFG |= 6; //配置系统时钟48MHz
// CLOCK_CFG |= 8; //配置系统时钟36MHz
// CLOCK_CFG |= 10; //配置系统时钟28.8MHz
CLOCK_CFG |= 12; //配置系统时钟24MHz
// CLOCK_CFG |= 16; //配置系统时钟18MHz
/*56MHz
// CLOCK_CFG &= ~MASK_SYS_CK_DIV;
// CLOCK_CFG |= 6; //配置系统时钟56MHz
PLL_CFG = 0xFC;
*/
SAFE_MOD = 0xFF; //关闭安全模式
// 如果修改主频,要同时修改FREQ_SYS,否则会造成延时函数不准
#endif
以上是关于CH559L单片机DMA方式在手工选择通道模式下AD采样数据串口输出的主要内容,如果未能解决你的问题,请参考以下文章