CH559L单片机ADC多通道采样数据串口打印案例
CH559L单片机ADC多通道采样数据串口打印案例
- ✨本案例基于Keil环境下开发。
- 📌案例来源WCH官网地址:
https://www.wch.cn/products/CH559.html
根据ADC采样通道的选择分为:单通道采样和多通道采样,根据ADC数据的转换处理分:DMA方式自动AD采样和手动方式AD采样。
⛳DMA方式自动AD采样案例测试
- 官方所给的示例代码如下:
来自:
ADCAUTODMA.C
文件
/********************************** (C) COPYRIGHT *******************************
* File Name : ADCAutoDMA.C
* Author : WCH
* Version : V1.3
* Date : 2016/6/24
* Description : CH559的ADC自动DMA方式采样操作,设置采样通道为0和1轮测,采样位数设置为11位
*******************************************************************************/
#include "..\DEBUG.C" //调试信息打印
#include "..\DEBUG.H"
#define ADCCount 2
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()
{
//P10-P17对应AIN0~AIN7:8 通道 ADC 模拟信号输入。
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 channel control mode
ADC_CTRL &= ~bADC_CHANN_MOD1; //1101 1111
ADC_CTRL |= bADC_CHANN_MOD0; //0001 0000 自动通道选择通道0和通道1
ADC_EX_SW |= bADC_RESOLUTION;//采样位数11bit
// ADC_EX_SW &= ~bADC_RESOLUTION; //采样位数10bit
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("%02u ",(UINT16)ADC_STAT);//ADC 状态寄存器 :11111000
if(ADC_STAT & bADC_IF_DMA_END) //DMA完成中断
{
Flag = 1;
ADC_STAT |= bADC_IF_DMA_END; //清中断
}
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; //清中断
}
}
void main( )
{
UINT8 i;
mDelaymS(30); //上电延时,等待内部晶振稳定,必加
CfgFsys( ); //CH559时钟选择配置
mInitSTDIO( ); //串口0,可以用于调试
printf("CH559L start ...\n");
Flag = 0;
//ADC采样有8个通道,在P1口,通道n 分别ADC_CHANN对应 (0x01 << n) ,如通道0是0x01,通道1是0x02依次类推
// ADC_CHANN =0x01 << 5;
InitADCInterrupt(); //ADC自动采样初始化
InitADCAuto();//ADC中断初始化
InitADCDMA();
EA = 1; //开启全局中断
while(1)
{
if(Flag)
{
for(i=1;i<29;i++)
{
printf("%04u ",ADCbuf[i]); //初次采样值建议丢弃
}
Flag = 0;
// ADC_DMA_CN = ADCCount ;//DMA 剩余计数寄存器重新赋值,否则不重新数据转换
mDelaymS(1000);
}
}
}
- 串口打印的结果:
并未实现DMA自动采样并连续打印的效果,只有在复位后重启后才打印一次采用的数据。上面的打印数据是烧录官方所提供的Hex文件,打印的结果。本想自己来找出bug来补上,看了半天的CH559手册上的ADC寄存器真的很难看懂,以前吐槽STC单片机手册都是1000+页的资料难翻阅,现在看到了WCH的70+页的数据手册,感觉不够看,关键是看不懂。感叹STC单片机手册详细,STM32的描述的明白。目前还没有找到清标志位的地方。
🎯手动采样案例
/********************************** (C) COPYRIGHT *******************************
* File Name : ADCManual.C
* Author : WCH
* Version : V1.3
* Date : 2016/6/24
* Description : CH559的手动采样ADC操作,支持通道切换
*******************************************************************************/
#include "..\DEBUG.C" //调试信息打印
#include "..\DEBUG.H"
UINT8 ADCChannel[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //ADC通道1-8
// #define _INT_ 1 //ADC中断方式
//#define mul_channel //启用代表0-8个通道一起采集,不启用则单通道采集
#define Single_channel 2 //如果选择单通道数据采集,指定单通道号:0-7
#pragma NOAREGS
/*******************************************************************************
* Function Name : InitADCManual()
* Description : ADC手动采用初始化
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void InitADCManual()
{
P1_IE = 0x00; //关闭P1口其他数据功能,如果只用到部分采样通道,其余置1,否则影响IO功能
ADC_SETUP |= bADC_POWER_EN; //ADC电源使能
ADC_CK_SE = 0x02; //设置分频
ADC_CTRL &= ~MASK_ADC_CYCLE; //选择手动采样
ADC_CTRL &= ~(bADC_CHANN_MOD1 | bADC_CHANN_MOD0); //手动选择通道
ADC_CHANN = ADCChannel[0]; //选通通道1
ADC_EX_SW |= bADC_RESOLUTION; //采样位数11bit
// ADC_EX_SW &= ~bADC_RESOLUTION; //采样位数10bit
mDelayuS(100); //确保ADC正常启动
}
/*******************************************************************************
* Function Name : ADCChanelChange()
* Description : ADC通道切换
* Input : UINT8 Chanel
* Output : None
* Return : UINT16 ADCValue
*******************************************************************************/
UINT16 ADCChanelChange(UINT8 Chanel)
{
UINT16 ADCValue = 0;
ADC_CHANN = Chanel; //切换ADC通道
// ADC_EX_SW |= bADC_RESOLUTION; //ADC采集位数
mDelayuS(10); //可选,等待通道切换成功
ADC_CTRL |= bADC_SAMPLE; //手动产生采样脉冲
mDelayuS(5);
ADC_CTRL &= ~bADC_SAMPLE;
while((ADC_STAT & bADC_IF_ACT) == 0); //非中断方式,等待采集完成
ADC_STAT |= bADC_IF_ACT;
ADCValue = ADC_FIFO;
return ADCValue; //返回采样值
}
#ifdef _INT_
/*******************************************************************************
* 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 : ADCInterrupt(void)
* Description : ADC 中断服务程序
*******************************************************************************/
void ADCInterrupt( void ) interrupt INT_NO_ADC using 1 //ADC中断服务程序,使用寄存器组1
{
UINT16 ADCValue = 0;
if(ADC_STAT & bADC_IF_ACT) //ADC完成中断
{
ADC_STAT |= bADC_IF_ACT; //清中断
}
ADCValue = ADC_FIFO;
printf("FIFOCnt:%02u ADC_DATA:%04u \n",(UINT16)(ADC_STAT&3),(UINT16)ADC_FIFO);
/* 如果需要继续采样,则使能下面程序,产生手工采样脉冲 */
#if 1
ADC_CTRL |= bADC_SAMPLE; //手动产生采样脉冲
mDelayuS(2);
ADC_CTRL &= ~bADC_SAMPLE;
#endif
}
#endif
void main( )
{
UINT16 ADCDat;
UINT8 i = 0;
CfgFsys( ); //CH559时钟选择配置
mDelaymS(5); //等待内部晶振稳定
mInitSTDIO( ); //串口0,可以用于调试
printf("start ...\n");
//ADC采样有8个通道,在P1口,通道n 分别ADC_CHANN对应 (0x01 << n) ,如通道0是0x01,通道1是0x02依次类推
InitADCManual(); //ADC手动采样初始化
ADCDat=ADC_FIFO; //ADC开启后,FIFO中有一个无效的采样值,取出丢弃
printf("FIFOCnt:%02u InvalidADC_DATA:%04u \n",(UINT16)(ADC_STAT&3),(UINT16)ADCDat);
#ifdef _INT_
InitADCInterrupt(); //ADC中断初始化
EA = 1; //开启全局中断
ADC_CTRL |= bADC_SAMPLE; //手动产生采样脉冲
mDelayuS(2);
ADC_CTRL &= ~bADC_SAMPLE;
#endif
while(1) //可以如果不用中断方式,可以查询bADC_IF_ACT位,为1代表手动采样成功
{
#ifndef _INT_
ADC_SETUP|=bADC_POWER_EN; //开启ADC电源
#ifdef mul_channel
for(i=0;i<8;i++){
ADCDat = ADCChanelChange(ADCChannel[i]); //通道i采样
printf("FIFOCnt:%02u ADC_DATA_P1%u:%04u \n",(UINT16)(ADC_STAT&3),(UINT16)i,(UINT16)ADCDat);
}
#else
ADCDat = ADCChanelChange(ADCChannel[Single_channel]);
printf("FIFOCnt:%02u ADC_DATA_P1%u:%04u \n",(UINT16)(ADC_STAT&3),(UINT16)1,(UINT16)ADCDat);
#endif
ADC_SETUP&=~bADC_POWER_EN; //关闭ADC电源
printf("-----我是分隔符------\n");
mDelaymS(1000);
//如果同时采样多个通道,可以在采样完成后通过bADC_CHANN_ID区分采样值所属的通道
#endif
}
}
- 指定单通道
P1_2
采样数据串口数据打印的结果
- 将上面的代码改成多通道一起采用并打印;
启用和注释对应的宏定义即可
#define mul_channel //启用代表0-8个通道一起采集,不启用则启用下面的单通道采集
//#define Single_channel 2 //如果选择单通道数据采集,指定单通道号:0-7
在这里源码就不提供了,根据上面提供的官方的参考源码以及上面附的代码修改对应内容即可验证。