当前位置: 首页 > news >正文

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

在这里插入图片描述

在这里源码就不提供了,根据上面提供的官方的参考源码以及上面附的代码修改对应内容即可验证。

相关文章:

  • 2022保研夏令营/预推免记录:浙大计院直博/西湖电子直博/南大软院/厦大信院
  • windows域KCC知识点
  • 优化树莓派上的网站:免费申请SSL证书 3/4
  • 深度学习梯度下降优化算法(AdaGrad、RMSProp、AdaDelta、Adam)(MXNet)
  • 2022 最新的 Java 八股文合集来了,彻底解决各大大厂面试难题
  • 【SSM框架】Mybatis详解11(源码自取)之事务,缓存,ORM
  • Maven 基本使用及依赖管理。
  • 数组是内存的实现及栈和队列的数据结构
  • 记录:2022-9-30 打家劫舍 二叉搜索树中第K小的元素 公平锁 磁盘调度
  • 基于html宠物用品商城项目的设计与实现(学生网页设计作业源码)
  • 【Java复习】线程安全的 HashMap --- ConcurrentHashMap
  • 《文化相对论》:危机重重的世界,对话才能产生转机
  • 水溶性CuInS/ZnS 量子点 PL 550 nm--800 nm
  • Vue3和react状态管理之Redux与Pinia的使用比较
  • 新学期如何克服“社恐”,猿辅导老师给高中生三条建议
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • 30天自制操作系统-2
  • canvas 高仿 Apple Watch 表盘
  • quasar-framework cnodejs社区
  • redis学习笔记(三):列表、集合、有序集合
  • swift基础之_对象 实例方法 对象方法。
  • vue脚手架vue-cli
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 前端面试之闭包
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 数据可视化之 Sankey 桑基图的实现
  • 微信小程序--------语音识别(前端自己也能玩)
  • 在Mac OS X上安装 Ruby运行环境
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (1)常见O(n^2)排序算法解析
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (20050108)又读《平凡的世界》
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • ./configure、make、make install 命令
  • .CSS-hover 的解释
  • .dwp和.webpart的区别
  • .equals()到底是什么意思?
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .net中的Queue和Stack
  • .NET中使用Redis (二)
  • @property括号内属性讲解
  • [<MySQL优化总结>]
  • [APIO2015]巴厘岛的雕塑
  • [cocos2d-x]关于CC_CALLBACK
  • [JavaScript]_[初级]_[不使用JQuery原生Ajax提交表单文件并监听进度]
  • [java后端研发]——文件上传与下载(2种方式)
  • [LeetCode] 178. 分数排名
  • [LeetCode]: 145: Binary Tree Postorder Traversal
  • [Linux] Ubuntu install Miniconda
  • [Linux]Ubuntu noVNC使用
  • [Paper]Cardiologist-Level Arrhythmia Detection with Convolutional Neural Networks