华润微8051系列通用MCU教程(6)---CS88F003之ADC使用

一:ADC介绍;

ADC是一种模数转换器,主要作用是将真实世界产生的如温度、压力、声音、指纹或者图像等模拟信号转换成更容易处理的数字形式。ADC/DAC的简要工作原理和过程如下图所示:
在这里插入图片描述

CS88F003 内嵌一个分辨率为 12 位的逐次逼近型模拟数字转换器(ADC),A/D 模块负责将管脚上的模拟电压信号转换为 12 位二进制数据。其支持8通道单端外部输入模式和内部1.2V带隙基准VBG输入模式,并且还支持比较输出功能,其模块时钟源由系统时钟提供,参考电压 VREF 可选择电源电压VDD 或者 PT30 外部输入电压。
CS88F003 ADC模块框图如下图所示:
在这里插入图片描述

二:CS88F003 ADC模块使用;

使用注意点:
①:不管是否使用中断,想要开启一次转换,就必须重新设置ADCON寄存器的bit4位一次;
②:CS88F003ADC只能选择VDD或者外部(PT30)作为参考电压;
③:此芯片的ADC转换速率不要设置为最快,设置为中等即可!

2.1:通过轮询方式等待ADC转换完成;

ADC模块配置步骤:

/**
	* @name Adc_init
	* @功能 :初始化ADC模块
	* @param	无
	* @retval: 	无
*/
void Adc_init(void)
{
	/*1:第一步关闭校准,选择基准电压*/
	ADOC = 0;
	/*2:第二步设置ADC周期和采样时间*/
	ADT = 0x83;
	/*3:第三步选择读取ADC的转换值*/
	ADDL &= ~(0x10);
}

获取ADC通道采样值步骤:

/**
	* @name Adc_get_value
	* @功能 :获取ADC通道的采样值
	* @param	adc_ch 需要读取的通道号
		@arg	0--AN0
		@arg	1--AN1
		@arg	2--AN2
		@arg	3--AN3
		@arg	4--AN4
		@arg	5--AN5
		@arg	6--AN6
		@arg	7--AN7
	* @retval: 	adc_value 相应通道的ADC采集值
		*通道的值如果返回0xffff,说明转换异常!
*/
Uint_16U Adc_get_value(Uint_8U adc_ch)
{
	Uint_16U timeout = 0;
	Uint_16U adc_value = 0xffff;
	Uint_8U  addl_value = 0;
	/*确保只读取AN0~AN7通道*/
	adc_ch &= 0x07;
	/*1:第一步打开ADC模块关闭比较功能*/
	ADCON = 0x80;
	/*2:第二步选择ADC通道*/
	ADCON |= adc_ch;
	/*3:第三步启动ADC转换*/
	ADCON |= 0x10;
	/*4:第四步等待ADC转换完成*/
	while((ADCON & 0x10))
	{
		timeout++;
		if(timeout > 1000)
		{
			/*超时还未转换完成,外部程序应该对此判断出错*/
			timeout = 0;
			/*返回0xffff代表转换异常*/
			return adc_value;
		}
	}
	//6:第六步获取转换值
	/*获取转换结果高位值*/
	adc_value = ADDH;
	adc_value <<= 4;
	/*获取转换结果低位值*/
	addl_value = ADDL;
	addl_value &= 0x0f;
	/*合并高低位值,返回ADC转换值*/
	adc_value += addl_value;
	return adc_value;
}

轮询等待方式读取ADC值实验主函数程序:

/******************************************************************************************
程序说明:本程序主要是验证ADC的采集功能。主要逻辑是配置ADC模块后,在轮询系统中开启转换,然后读出转
换后的ADC值,最后再通过串口将AD值发出,可用逻辑分析仪查看。
注:
	①:注意如果是测试的话最好通过直流电源给到ADC的输入口,因为当你想用ADC去采集PWM的平均电压时,
	很有可能出现采集值差别很大。除非ADC的采集频率远大于PWM频率,采集多次后取平均值!
	②:CS88F003存储模式是大端模式,即高位存储在地址低位。
	③:	ADC_CH0----PT17
		TXD--------PT16
	④:输入电压不能大于VDD
*******************************************************************************************/
void uart1_send_init(void);
void uart1_send_data(Uint_8U *buff, Uint_16U str_len);
void main(void)
{
	Uint_16U adc_ch0_value;
	Sys_Clk_Set_IRCH(SYS_CLK_8M); //芯片默认校准为16M,分频后系统主频8M
	SysClk_Delay(50);
	WDT_OFF(); 
	
	/*初始化ADC模块*/
	Adc_init();
	/*初始化uart1模块*/
	uart1_send_init();
	while(1)
	{
		/*获取ADC-CH0的采样值*/
		adc_ch0_value = Adc_get_value(0);
		/*将采样数据发出,注意003是大端存储模式*/
		uart1_send_data((Uint_8U *)&adc_ch0_value,2);
		SysClk_Delay(50);
	}
}
/*************************************************uart1函数************************************************/
/**
	* @name uart1_send_init
	* @功能 :初始化uart1模块
	* @param	无
	* @retval: 	无
*/
void uart1_send_init(void)
{
	/*使能端口复用寄存器,PT16复用为UART1_TXD*/
	PT1_MUX0 |= 0x40;
	/*设置uart模块的频率,uart1选择1分频也就是模块频率等于系统主频*/
	UART1_CLKS = 0x00;
	/*设置uart传输数据的波特率,uart1传输速率设置为115200*/
	UART1_CLKDIVH = 0x00;
	UART1_CLKDIVL = 0x45;
	/*设置uart模块的帧格式,uart1设置为10位帧格式(1起始+8数据+1停止)*/
	UART1_CTRL &= ~(0x06);
	/*使能uart1模块*/
	UART1_CTRL |= 0x01;
}

/**
	* @name uart1_send_data
	* @功能 :串口输出接口
	* @param	
		@arg 	buff 	需要输出数组
		@arg	str_len	数组大小
	* @retval: 	无
*/
void uart1_send_data(Uint_8U *buff, Uint_16U str_len)
{
	Uint_16U i;
	for(i=0;i<str_len;i++)
	{
		UART1_TXD = buff[i];
		while(UART1_STATE & 0x40);
	}
}

2.2:通过中断方式检测ADC是否转换完成;

ADC模块配置步骤:

/**
	* @name Adc_Int_init
	* @功能 :初始化ADC模块
	* @param	adc_ch 需要读取的通道号
		@arg	0--AN0
		@arg	1--AN1
		@arg	2--AN2
		@arg	3--AN3
		@arg	4--AN4
		@arg	5--AN5
		@arg	6--AN6
		@arg	7--AN7
	* @retval: 	无
*/
void Adc_Int_init(Uint_8U adc_ch)
{
	/*1:第一步关闭校准,选择基准电压*/
	ADOC = 0;
	/*2:第二步设置ADC周期和采样时间*/
	ADT = 0x83;
	/*3:第三步选择读取ADC的转换值*/
	ADDL &= ~(0x10);
	/*4:第四步打开ADC模块关闭比较功能*/
	ADCON = 0x80;
	/*5:第五步确保只读取AN0~AN7通道*/
	adc_ch &= 0x07;
	/*6:第六步选择ADC通道*/
	ADCON |= adc_ch;
	/*7:第七步选择ADC中断输出口,INT0*/
	IRQ_SEL0 |= 0x04;
	/*8:第八步使能ADC中断*/
	IRQ_EN0 |= 0x04;
	/*9:第九步使能全局中断和INT0*/
	IE = 0x81;
	/*10:第十步启动ADC开始转换*/
	ADCON |= 0x10;
}

中断处理程序逻辑步骤:

volatile Uint_16U adc_value = 0;	//ADC值
volatile Uint_8U  addl_value = 0;	//寄存器低位值
volatile Uint_8U adc_flag = 0;		//转换标志位
void IRQ_0() interrupt 0 
{
	/*1:第一步判断是否产生了ADC中断*/
	if(IRQ_STAT0 & 0x04)
	{
		/*2:第二步清除中断标志位*/
		IRQ_CLR0 |= 0x04;
		/*3:第三步判断是否转换完成*/
		if(!(ADCON & 0x10))
		{
			//4:第四步获取转换值
			/*获取高位寄存器值*/
			adc_value = ADDH;
			adc_value <<= 4;
			/*获取低位寄存器值*/
			addl_value = ADDL;
			addl_value &= 0x0f;
			/*adc值*/
			adc_value += addl_value;
			/*5:第五步根据需要重新开启ADC转换*/
			ADCON |= 0x10;
			/*置位标志,可在外部使用ADC值*/
			adc_flag = 1;
		}
	}
}

中断检测方式读取ADC值实验主函数程序:

/******************************************************************************************
程序说明:本程序主要是验证ADC的采集功能(在中断中获取ADC值)。主要逻辑是配置ADC模块后,当ADC转换完
成触发中断,然后读出转换后的ADC值,最后再通过串口将AD值发出,可用逻辑分析仪查看。
注:
	①:注意如果是测试的话最好通过直流电源给到ADC的输入口,因为当你想用ADC去采集PWM的平均电压时,
	很有可能出现采集值差别很大。除非ADC的采集频率远大于PWM频率,采集多次后取平均值!
	②:CS88F003存储模式是大端模式,即高位存储在地址低位。
	③:	ADC_CH0----PT17
		TXD--------PT16
	④:输入电压不能大于VDD
*******************************************************************************************/
extern volatile Uint_16U adc_value ;	//ADC值
extern volatile Uint_8U adc_flag ;		//转换标志位
void uart1_send_init(void);
void uart1_send_data(Uint_8U *buff, Uint_16U str_len);
void main(void)
{
	Sys_Clk_Set_IRCH(SYS_CLK_8M); //芯片默认校准为16M,分频后系统主频8M
	SysClk_Delay(50);
	WDT_OFF(); 
	
	/*初始化ADC模块*/
	Adc_Int_init(0);
	/*初始化uart1模块*/
	uart1_send_init();
	while(1)
	{
		if(adc_flag)
		{
			uart1_send_data((Uint_8U*)&adc_value, 2);
			adc_flag = 0;
		}
		SysClk_Delay(50);
	}
}
/*************************************************uart1函数************************************************/
/**
	* @name uart1_send_init
	* @功能 :初始化uart1模块
	* @param	无
	* @retval: 	无
*/
void uart1_send_init(void)
{
	/*使能端口复用寄存器,PT16复用为UART1_TXD*/
	PT1_MUX0 |= 0x40;
	/*设置uart模块的频率,uart1选择1分频也就是模块频率等于系统主频*/
	UART1_CLKS = 0x00;
	/*设置uart传输数据的波特率,uart1传输速率设置为115200*/
	UART1_CLKDIVH = 0x00;
	UART1_CLKDIVL = 0x45;
	/*设置uart模块的帧格式,uart1设置为10位帧格式(1起始+8数据+1停止)*/
	UART1_CTRL &= ~(0x06);
	/*使能uart1模块*/
	UART1_CTRL |= 0x01;
}

/**
	* @name uart1_send_data
	* @功能 :串口输出接口
	* @param	
		@arg 	buff 	需要输出数组
		@arg	str_len	数组大小
	* @retval: 	无
*/
void uart1_send_data(Uint_8U *buff, Uint_16U str_len)
{
	Uint_16U i;
	for(i=0;i<str_len;i++)
	{
		UART1_TXD = buff[i];
		while(UART1_STATE & 0x40);
	}
}

2.3:ADC的比较功能;

功能介绍: 003的ADC比较功能实际上就是一个阈值电压,初始时设置好阈值,当AD口采集到的电压大于或者小于这个阈值时就会触发中断。但是我根据实测发现,这个中断在仿真全速运行时只能触发一次,除非重新进仿真,也就是说这个功能是一次性的。

ADC模块配置步骤:

/**
	* @name Adc_Cmp_init
	* @功能 :配置ADC比较模式
	* @param	adc_ch 需要比较的通道
		@arg	0--AN0
		@arg	1--AN1
		@arg	2--AN2
		@arg	3--AN3
		@arg	4--AN4
		@arg	5--AN5
		@arg	6--AN6
		@arg	7--AN7
	* @retval: 	无
*/
void Adc_Cmp_init(Uint_8U adc_ch)
{
	/*1:第一步关闭校准,选择基准电压*/
	ADOC = 0;
	/*2:第二步设置ADC周期和采样时间*/
	ADT = 0x83;
	/*3:第三步选择读取ADC的转换值*/
	ADDL &= ~(0x10);
	/*4:第四步打开ADC模块,开启比较功能,选择比较模式,例如选择大于模式*/
	ADCON = (0x80 | 0x40 |0x20);
	/*5:第五步选择ADC通道*/
	ADCON |= adc_ch;
	/*6:第六步选择ADC中断输出口,INT0*/
	IRQ_SEL0 |= 0x04;
	/*7:第七步使能ADC中断*/
	IRQ_EN0 |= 0x04;
	/*8:第八步使能全局中断和INT0*/
	IE = 0x81;
	/*9:第九步设置比较电压值,例如当检测到电压大于3v,触发一次中断*/
	ADDH = 0x99;
	ADDL = 0x09;
	/*10:第十步启动ADC开始转换*/
	ADCON |= 0x10;
}

中断处理程序逻辑步骤:

volatile Uint_16U adc_value = 0;	//ADC比较值
volatile Uint_8U addl_value = 0;	//低位寄存器值
volatile Uint_8U adc_flag = 0;		//比较器中断标志
void IRQ_0() interrupt 0 
{
	/*1:第一步判断是否产生了ADC中断*/
	if(IRQ_STAT0 & 0x04)
	{
		/*2:第二步清除中断标志位*/
		IRQ_CLR0 |= 0x04;
		/*翻转pt00引脚电平*/
		PT0_DOUT ^= 0x01; 
		/*置位标志,说明ADC采样值触发比较器中断了*/
		adc_flag = 1;
		/*3:可以选择性读取此时adc转换值*/
		if(!(ADCON & 0x10))
		{
			adc_value = ADDH;
			adc_value <<= 4;
			addl_value = ADDL;
			addl_value &= 0x0f;
			adc_value += addl_value;
		}
	}
}

ADC比较功能实验主函数程序:

/*****************************************************************************************************************
程序说明:本程序主要是验证ADC的比较功能,其基本逻辑是在主程序中配置好ADC的比较功能后就在轮询系统中检测中断标志,
一旦电压大于3v,触发中断后标志位就会置1,并且还会在中断中将PT00引脚翻转,最后在轮询系统中通过串口将采样值发送出去;
注:
	①:注意如果是测试的话最好通过直流电源给到ADC的输入口,因为当你想用ADC去采集PWM的平均电压时,
	很有可能出现采集值差别很大。除非ADC的采集频率远大于PWM频率,采集多次后取平均值!
	②:CS88F003存储模式是大端模式,即高位存储在地址低位。
	③:	ADC_CH0----PT17
		TXD--------PT16
	④:输入电压不能大于VDD
	⑤:例如在VDD=5V时选择触发模式为大于模式,设置的比较值是0x999(换算电压为3v),当ADC采集的引脚电压大于3v时,
	则会触发ADC中断。
	⑥:经测试在整个程序运行周期内只会触发一次中断,例如设置了3V的比较值,在程序运行时检测到一次3.5v触发了中断,
	即使后面再次检测到3.5v也不会响应中断了!
****************************************************************************************************************/
extern volatile Uint_16U adc_value;		//ADC转换值
extern volatile Uint_8U adc_flag ;		//转换标志位
void uart1_send_init(void);
void uart1_send_data(Uint_8U *buff, Uint_16U str_len);
void main(void)
{
	Sys_Clk_Set_IRCH(SYS_CLK_8M); //芯片默认校准为16M,分频后系统主频8M
	SysClk_Delay(50);
	WDT_OFF(); 
	
	/*初始化IO口,PT00初始置高电平*/
	PT0_OE |= 0x01; 
	PT0_DOUT |= 0x01; 
	/*初始化ADC模块*/
	Adc_Cmp_init(0);
	/*初始化uart1模块*/
	uart1_send_init();
	while(1)
	{
		/*如果触发比较中断,则通过串口将触发中断时的AD值发送出去*/
		if(adc_flag)
		{
			uart1_send_data((Uint_8U *)&adc_value, 2);
			adc_flag = 0;
		}
		SysClk_Delay(50);
	}
}
/*************************************************uart1函数************************************************/
/**
	* @name uart1_send_init
	* @功能 :初始化uart1模块
	* @param	无
	* @retval: 	无
*/
void uart1_send_init(void)
{
	/*使能端口复用寄存器,PT16复用为UART1_TXD*/
	PT1_MUX0 |= 0x40;
	/*设置uart模块的频率,uart1选择1分频也就是模块频率等于系统主频*/
	UART1_CLKS = 0x00;
	/*设置uart传输数据的波特率,uart1传输速率设置为115200*/
	UART1_CLKDIVH = 0x00;
	UART1_CLKDIVL = 0x45;
	/*设置uart模块的帧格式,uart1设置为10位帧格式(1起始+8数据+1停止)*/
	UART1_CTRL &= ~(0x06);
	/*使能uart1模块*/
	UART1_CTRL |= 0x01;
}

/**
	* @name uart1_send_data
	* @功能 :串口输出接口
	* @param	
		@arg 	buff 	需要输出数组
		@arg	str_len	数组大小
	* @retval: 	无
*/
void uart1_send_data(Uint_8U *buff, Uint_16U str_len)
{
	Uint_16U i;
	for(i=0;i<str_len;i++)
	{
		UART1_TXD = buff[i];
		while(UART1_STATE & 0x40);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值