资源描述
《微机控制系统及其应用》
课程实验报告
实验一 代码转换
一、 实验时间及地点
电信学院西1楼,2011年11月13日
二、 实验目的
熟悉C8051单片机常用代码之间的转换方法。
三、实验任务
1. 设计并调试一个程序,将片内20H单元中8位无符号二进制数转化为BCD码,结果存入以30H开始的单元中。
2. 设计并调试一个程序,将片内以20H开始的单元中的4字节无符号二进制数转化为BCD码,结果存入以30H开始的单元中,低位字节在低地址端。
3. 设计并调试一个程序,将累加器A中的二进制数(0~F)转化为ASCⅡ码,结果仍放在A中。
四、实验原理
二进制数转换BCD码
将无符号二进制数转换为BCD码,实质是将二进制数转换为十进制数,但是这里的十进制数中的每一位用BCD码来表示,进制转换的原理实质是按权展开。设需转换的二进制数为a,a%10即得到所需要的十进制数的最低位数,(a/10)%10得到十进制数的高一位数,依次类推,可以进行多位无符号二进制数到BCD码的转换。本次实验是将8位无符号数转换为转化为BCD码,即0~255。
二进制数(0~F)转化为ASCⅡ码
0~F的二进制数转换为ASCⅡ码,关系可表示如下:
五、实验内容及步骤
1、启动计算机,进入仿真环境,完成进行初始化设置。
2、编译无误后,运行程序,打开数据窗口(DATA),点击暂停按钮,观察地址30H、31H、32H的数据变化,30H更新为01,31H更新为02,32H更新为03。用键盘输入改变地址30H、31H、32H的值,点击复位按钮后,可再次运行程序,观察其实验效果。修改源程序中给累加器A的赋值,重复实验,观察实验效果。
六、实验运行及结果
1.8位无符号二进制数转化
程序流程图
将二进制数给指定指针变量
将数除以100,得百位数
保存百位数
将余数再除以10,得十位数
保存十位数
余数为个位数,将其保存到指定指针变量中
结束
C语言源程序
void main()
{
unsigned char *a,*b;
WDTCN = 0xde;
WDTCN = 0xad;
SYSCLK_Init();
PORT_Init();
a=0x20;b=0x30;
*a=0xA8H;
*b=*a/100;
b++;
*b=(*a-(*a/100)*100)/10;
b++;
*b=*a%10;
while(1);
}
编译结果
片内20H单元中8位无符号二进制数#A8h,转换为十进制数为168,其BCD码为168,将其存入30H开始的单元中,从低位到高位分别为#01h,#06h,#08h;
结果如下图所示:
2.4字节无符号二进制数转化为BCD码
程序流程图
定义一个地址指针
设定一个待转换的初始值,将其放入指定指针变量
除10得到除数和余数
将余数存入30H开头的地址内
否
除数为0
是
除数除10得到新的除数和余数
将余数存入地址加一的新地址内
除数除10得到除数和余数
结束
C语言源程序`
void main()
{
unsigned char i;
unsigned long tempp;
ori=0x20;
*ori=0x00000400;
tempp=*ori;
temp=0x30;
for(i=10;i--;i>0)
{
*temp=tempp%10;
tempp=tempp/10;
temp++;
}
while(1);
}
编译结果
片内以20H开始的单元中的4字节无符号二进制数为0xFEEFFFFFh,其BCD码为141503,将其存入30H开始的单元中,从低位到高位分别为#03h,#00h,#05h,#01h,#04h,#01h,结果如下图所示:
3.ASCII码转换
将累加器A中的二进制数(0~F)转化为ASCⅡ码,结果仍放在A中,从ASCII编码表中可知,若4位二进制数小于10,则在此二进制数上加30H即变为相应的ASCII码;若≥10,则应加37H方可。本次实验取cH进行转换。
程序流程图将预转换二进制数存入A
A≥10
N
Y
加30H
加37H
将转换后的值存入A中
结束
C语言源程序
#include <c8051F020.h>
void main (void)
{
char y;
ACC=0x0b;
y=ACC;
if (y<0x0c)
y=y+0x30;
else
y=y+0x37;
ACC=y;
while(1);
}
编译结果
程序运行后,转换后结果存放入A中。本例中A中预转换的二进制数为0BH,转化为ASCⅡ码后A寄存器中为43H,结果如下图所示:
七、注意事项及结果分析
1. 8位无符号二进制表示的十进制范围是0~255,检验结果时应检查32H,31H,30H对应的结果是否正确。4字节无符号二进制数示的十进制范围:0~4,294,967,295(即232-1)。转换为BCD码形式需设置10个字节进行存储。
2.二进制数为4字节无符号数故需设置为unsigned long 型,指针需分别设成unsigned long和unsigned char 型,否则会出错。
实验二 液晶显示程序设计
一、实验时间及地点
电信学院西1楼,2011年11月20日
二、实验目的
掌握C8051单片机液晶显示程序设计方法。
三、实验任务
1. 设计并调试一个显示程序,利用所提供液晶显示器滚动显示123456这六个数字,并以每字符500毫秒的速度向右移动循环。
2. 实现秒表计时功能。用键盘产生中断控制秒表的开始和停止。
3. 实现日历功能,并将日历显示在液晶屏上。
四、编程原理及实验运行结果
1. 滚动数字显示
程序流程图:开始
确定好显示数字位置,定义坐标
横坐标设为初始值
进行定时,定时间隔500ms
横坐标超液晶横向
点数上限
是
否
液晶显示坐标变换,横坐标增加特定值
子程序描述
数字的显示函数:
void LCDC_DispWord (unsigned char x, y, unsigned char code *p, unsigned char line, length, Flag),其中x、y表示显示字符的坐标,*p表示显示字符的代码。
延时函数:实际中起到定时作用。
void Delay_ms(unsigned int times),其中times表示延时的毫秒数。
利用LCDC_DispWord()函数显示数据,利用Delay_ms()延时500ms,将数字循环移位。
C语言源程序
#include "main.h"
unsigned char key; //定义键值变量
void main (void)
{
int i;
//禁止看门狗定时器
WDTCN = 0xde;
WDTCN = 0xad;
//初始化
SYSCLK_Init ();
PORT_Init ();
Key_Init();
LCDC_Init();
LCDC_DisFull(Full);
Delay_ms(500);
LCDC_DisFull(Clr);
Delay_ms(500);
//dis_start0();
while(1)
{
for(j=0;j<20;j++)
{i=5*j;
LCDC_DispWord (0+i*5, 2, WLib_1_4x8, 1, 4, 1);
LCDC_DispWord (5+i*5, 2, WLib_2_5x8, 1, 5, 1);
LCDC_DispWord (10+i*5, 2, WLib_3_5x8, 1, 5, 1);
LCDC_DispWord (15+i*5, 2, WLib_4_6x8, 1, 6, 1);
LCDC_DispWord (20+i*5, 2, WLib_5_5x8, 1, 5, 1);
LCDC_DispWord (25+i*5, 2, WLib_6_5x8, 1, 5, 1);
Delay_ms(500);
LCDC_DisFull(Clr);
}
if(j>=20)
j=0; }}
编译结果
经编译调试后,液晶显示器滚动显示123456这六个数字。
2. 秒表计时功能
键盘控制实现
设置按键0,1,2的功能为开始、停止与暂停,设标志位flag,并初始化flag=0;当flag=1时(开始),进行计时变量的加1操作;当flag=2时(停止),将所有的计时变量清零,实现即时停止;当flag=3时(暂停),空操作,计时时间保持不变,从而实现暂停的功能。
程序开始
确定好显示数字位置,定义坐标
流程图
根据按键进入秒表开始、停止计数以及清零子程序
结束
扫描按键
C语言主程序
计时开始程序:
void time_start(void)
{
while (1)
{
dis_time(Ti++);
Delay_ms(2);
key=GetKey();
if (key==0x0e)
{
To=Ti;
break;
}}}
计时暂停程序:
void time_pause(void)
{
while (1)
{
dis_time(To);
key=GetKey();
if (key==0x0e)
{
Ti=To;break;
}
if (key==0x0d)
{
Ti=0;break;
}
}
}
时间显示程序:
void dis_time(unsigned int Times)
{
unsigned int Tm,Ts,Tms;
Tm=Times/6000;
Ts=(Times/100)%60;
Tms=Times%100;
dis_minute(Tm);
LCDC_DispWord (12, 2, WLib_ddot_3x8, 1, 3, 1);
dis_second(Ts);
LCDC_DispWord (30, 2, WLib_ddot_3x8, 1, 3, 1);
dis_milisecond(Tms);
}
主程序
void main (void)
{
//禁止看门狗定时器
WDTCN = 0xde;
WDTCN = 0xad;
//初始化
SYSCLK_Init ();
PORT_Init ();
Key_Init();
LCDC_Init();
LCDC_DisFull(Full);
Delay_ms(500);
LCDC_DisFull(Clr);
Delay_ms(500);
//dis_start0();
dis_time(Ti);
while(1)
{
key=GetKey(); //调用键盘扫描函数,返回的键值送变量key
if(key!=0xFF) //键值有效 执行按键程序
{
Alarm(1); //响铃
Delay_ms(50);
Alarm(0); //关闭铃声
switch (key)
{
case 0x0a:
time_start();
break;
case 0x0e:
time_pause();
break;
case 0x0d:
Ti=0;
dis_time(Ti);
break;
default: break;
}
}
}
}
编译结果
经编译后,液晶显示器上可以显示秒表时间,并通过按下按键“0x0a”后开始计数,按下按键“0x0e”后计数暂停,按下按键“0x0e”后计数值进行清零。
五、实验结果分析及注意事项
1. c语言中利用键盘扫描可以较简单的实现中断的功能。
2. 液晶屏对应的显示函数等编程要按一定的规范。
实验三 串行通讯程序设计
一、实验时间及地点
电信学院西1楼,2011年11月27日
二、实验目的
掌握C8051单片机串行通讯程序设计方法。
三、实验任务
设计并调试一个串行通讯程序,利用单片串行端口将片外RAM中以3000H为起始地址的1024个字节通过串行发送端口A输出,并以自闭环的形式由串行接收口B接收,并存储到以4000H为起始地址的空间中。
四、实验原理
1.串行口硬件介绍
C8051F020有2个增强型串行口,UART 0/1(Universal Asynchronous-Receiver and Transmitter)用于串行通信。它主要由发送缓冲器SBUF、接收缓冲器SBUF和移位寄存器、控制逻辑等部分组成。
单片机串行口传送的字符格式及波特率等可由软件编程决定,其功能由送入串行口中相关的控制寄存器的控制字格式而定。UART 0/1有4种工作方式,通过设置串行口控制寄存器SCON0的SM0(D7)、SM1(D6)来进行选用。
UART 0使用定时器1时,波特率为:
波特率=
式中:T1M为定时器1时钟选择位(CKON.4);
TH1为定时器1的8位重载寄存器。
UART 1使用定时器4时,波特率为:
波特率=
式中:为定时器4的重载寄存器。
串行传输的速率(波特率)与主振频率和CPU内的定时器有关。此外,波特率的选择还与距离相关,距离越近,可选择的最大波特率越大。在本实验中以自闭环形式传送,故选择最大波特率11520Hz。
2.功能子函数介绍
发送功能子函数
1) 串口初始化;
2) 等待发送1个字节数据完成;
3) 写入SBUF下一个要发送的数据;
4) 清除中断标志TI。
void Uart0_SendByte (unsigned char value)
{
while (!TI0); // 等待发送1个字节数据完成
SBUF0=value; // 发送数据到uart0
TI0=0; // 清除中断标志
}
串行口每发送完一帧数据后会自动置位中断请求标志位TI,这里利用此特点进行程序设计,即利用查询方式来查探传送过程,由于硬件不会自动清除中断请求标志位TI,故每次需要人为清零。
接收功能子函数
1) 串口初始化;
2) 若接收完毕,从SBUF读出数据,否则返回0XFF。
unsigned char Uart0_ReceiveData (void)
{
if (RI0)
{
SCON0&=~0x01; // 清除RI1标志位
return SBUF0;
}
return 0xff;
}
串行口每接收完一帧数据后会自动置位中断请求标志位RI,这里利用此特点进行程序设计,即利用查询方式来查探传送过程,由于硬件不会自动清除中断请求标志位RI,故每次需要人为清零。接收子函数中设置返回值便于程序检验,简单明了。
3.实现串口发送和接受
要实现片外数据的传送与接受,可以通过两个外部数字指针,指向需要发送数据的位置和接收数据的位置,调用发送和接收函数,将1024个字节通过串行发送端口A输出,并以自闭环的形式由串行接收口B接收。为了保证发送和接收数据的准确性,发送或数据后延迟5ms。
五、实验运行结果
主程序流程图:系统初始化
设置收发波特率
发送(重发)数据
接收数据
延时
延时
设置存储器初始值(以便检测)
Y
N
开始
是否接收到
准备发送下一位
结束束
C语言源程序
串口0发送程序
void Uart0_SendByte (unsigned char value)
{
while (!TI0); // 等待发送1个字节数据完成
SBUF0=value; // 发送数据到uart0
TI0=0; // 清除中断标志
}
串口1接收程序
unsigned char Uart1_ReceiveData (void)
{
if (RI0)
{
SCON1&=~0x02; // 清除RI1标志位
return SBUF0;
}
return 0xff;
}
主程序
void main (void)
{
unsigned char xdata *p1;
unsigned char xdata *p2;
unsigned char i,k,temp;
WDTCN=0xDE; //禁止看门狗定时器
WDTCN=0xAD;
SYSCLK_Init();
PORT_Init();
k=0;
p1=0x3000;
p2=0x4000;
for (i=0;i<1024;i++)
{
*p1=0x09;
p1++;
}
Uart0_Init(BaudRate_115200);
Uart1_Init(BaudRate_115200);
while(1)
{
Uart0_SendByte(*p1); //p1的数据通过串口0发送出去
Delay_ms(5);
temp=Uart1_ReceiveData(); //串口1接收的数据
Delay_ms(5);
if (temp!=0xff&&k<1024) //串口1接收的数据是否有效
{
*p2=temp;
p2++;
p1++;
k++;
}}}
编译结果
通过编写程序,在以3000H为起始地址的1024个字节中都写入09H。程序运行后,查看3000H~33FFH中写入的都是09H, 4000H~43FFH中接受到的从3000H~33FFH传来的数据都是09H,实现程序要求的功能。
部分运行结果数据如下图所示:
六、实验结果分析及注意事项
1. 试验预期达到的效果应该是从3000H开始循环存放00H—FEH,程序运行结束后以3000H为起始地址的1024个字节和以4000H为起始地址的1024个字节存放的结果同为00H—FEH。经试验检验,结果正确。
2. 注意事项
1) 由于传送的数据量大,程序的执行需要一定时间,如提前终止程序,会使得到的结果不正确,即:4000Hk开始的地址单元只有前一部分数据是正确的,高地址内的数据是随机的。
2) 程序中,当串口没有接收到数据时,默认的接受的返回值为0xff,因此传送的数据不能等于0xff,否则出错。传送的数据在程序中为单字节数据,故设置为unsigned char型,范围0x00~0xfe。
实验四 A/D转换实验
一、实验时间及地点
电信学院西1楼,2011年12月4日
二、实验目的
掌握C8051单片机A/D转换和时钟中断的程序设计方法。
三、实验任务
设计并调试一个A/D采样程序,使用外部22.1184MHz 晶振。利用定时器中断,每1秒钟中断一次并采样。采样AIN0,1和温度通道信号,并在LCD 上显示其电压和温度值。通过手动调节VR2电位器,观察电压值的变化。
四、编程原理及实验运行结果
本实验用AIN0对输入电压进行转换,并由LCD显示,同时显示通道1的电压值和温度值。设置ADC0使用定时器Timer3溢出作为转换源,转换完成后产生中断,使用左对齐输出模式。进行通道顺次转换时,对通道号i进行判断,i为0或1时进行相应转换并由LCD显示,i为8时对温度进行检测及显示。若为其他通道,则不响应。
流程图
C语言源程序
#include "main.h"
void main (void)
{
unsigned long voltage; // 电压值(毫伏)
unsigned long tp;
int i; // 循环计数器
WDTCN = 0xde;
WDTCN = 0xad;
SYSCLK_Init(); // 系统时钟初始化
PORT_Init(); // 系统端口初始化
LCDC_Init(); // LCD初始化
Timer3_Init(SYSCLK/SAMPLERATE0); // 初始化Timer3溢出的值
ADC0_Init (); // ADC初始化
LCDC_DisFull(Full); //满屏
LCDC_DisFull(Clr); //清屏
ADC0_enable(1); //ADC0使能
LCDC_DisFull(Clr); //清屏
while (1)
{
Delay_ms(500);
for (i=0;i<9;i++) // ADC0九个通道
{
Delay_ms(100);
DISABLE_INTERRUPTS; // 关闭中断
voltage = ADC_Valud_Return(i); // 给全局变量赋ADC的值
ENABLE_INTERRUPTS; // 重新开启中断
voltage = voltage * VREF0; // 实际电压
DISABLE_INTERRUPTS; // 关中断
switch(i)
{
case 0: // 通道0显示
LCDC_DispWord(0,48,WLib_tong_16x16,2,16,1);
LCDC_DispWord(16,48,WLib_dao_16x16,2,16,1);
LCDC_DispWord(32,48,&WLib_Num_8x16[i*32],2,8,1);
LCDC_DispWord(40,48,WLib_maohao_8x16,2,8,1);
LCDC_DispWord(112,48,WLib_fu_16x16,2,16,1);
voltage = voltage >> 16;
if(voltage > 0x0004E2)
{
voltage =8*(voltage-0x0004E2);
LCDC_DispWord(48,48,&WLib_Num_8x16[0],2,8,1);
LCDC_DispWord(56,48,&WLib_Num_8x16[voltage/10000*16],2,8,1);
LCDC_DispWord(64,48,&WLib_Num_8x16[voltage/1000*16],2,8,1);
LCDC_DispWord(72,48,WLib_dian_8x16,2,8,1);
LCDC_DispWord(80,48,&WLib_Num_8x16[voltage%1000/100*16],2,8,1);
LCDC_DispWord(88,48,&WLib_Num_8x16[voltage%100%100/10*16],2,8,1);
LCDC_DispWord(96,48,&WLib_Num_8x16[voltage%100%100%10*16],2,8,1);
}
else
{
voltage =8*(0x0004E2 - voltage); LCDC_DispWord(48,48,&WLib_Num_8x16[160],2,8,1);
LCDC_DispWord(56,48,&WLib_Num_8x16[voltage/10000*16],2,8,1);
LCDC_DispWord(64,48,&WLib_Num_8x16[voltage/1000*16],2,8,1);
LCDC_DispWord(72,48,WLib_dian_8x16,2,8,1);
LCDC_DispWord(80,48,&WLib_Num_8x16[voltage%1000/100*16],2,8,1);
LCDC_DispWord(88,48,&WLib_Num_8x16[voltage%100%100/10*16],2,8,1);
LCDC_DispWord(96,48,&WLib_Num_8x16[voltage%100%100%10*16],2,8,1);
}
break;
case 1: // 通道1显示
LCDC_DispWord(0,32,WLib_tong_16x16,2,16,1);
LCDC_DispWord(16,32,WLib_dao_16x16,2,16,1);
LCDC_DispWord(32,32,&WLib_Num_8x16[i*16],2,8,1);
LCDC_DispWord(40,32,WLib_maohao_8x16,2,8,1);
LCDC_DispWord(112,32,WLib_fu_16x16,2,16,1);
voltage = voltage >> 16;
if(voltage > 0x0004E2)
{
voltage =8*(voltage-0x0004E2);
LCDC_DispWord(48,32,&WLib_Num_8x16[0],2,8,1);
LCDC_DispWord(56,32,&WLib_Num_8x16[voltage/10000*16],2,8,1);
LCDC_DispWord(64,32,&WLib_Num_8x16[voltage/1000*16],2,8,1);
LCDC_DispWord(72,32,WLib_dian_8x16,2,8,1);
LCDC_DispWord(80,32,&WLib_Num_8x16[voltage%1000/100*16],2,8,1);
LCDC_DispWord(88,32,&WLib_Num_8x16[voltage%100%100/10*16],2,8,1);
LCDC_DispWord(96,32,&WLib_Num_8x16[voltage%100%100%10*16],2,8,1);
}
else
{
voltage =8*(0x0004E2 - voltage);
LCDC_DispWord(48,32,&WLib_Num_8x16[160],2,8,1);
LCDC_DispWord(56,32,&WLib_Num_8x16[voltage/10000*16],2,8,1);
LCDC_DispWord(64,32,&WLib_Num_8x16[voltage/1000*16],2,8,1);
LCDC_DispWord(72,32,WLib_dian_8x16,2,8,1);
LCDC_DispWord(80,32,&WLib_Num_8x16[voltage%1000/100*16],2,8,1);
LCDC_DispWord(88,32,&WLib_Num_8x16[voltage%100%100/10*16],2,8,1);
LCDC_DispWord(96,32,&WLib_Num_8x16[voltage%100%100%10*16],2,8,1);
}
break;
case 2: // 通道2显示
voltage = voltage >> 16;
if(voltage > 0x0004E2)
{
voltage =8*(voltage-0x0004E2);
}
else
{
voltage =8*(0x0004E2 - voltage);
}
break;
case 8: // 芯片温度显示 voltage = ADC_Valud_Return (8);
tp=(voltage/16-1324)*839/4096;
LCDC_DispWord(0,16,WLib_wen_16x16,2,16,1);
LCDC_DispWord(16,16,WLib_du_16x16,2,16,1);
LCDC_DispWord(32,16,WLib_maohao_8x16,2,8,1);
LCDC_DispWord(112,16,WLib_du_16x16,2,16,1);
LCDC_DispWord(64,16,&WLib_Num_8x16[tp/10*16],2,8,1);
LCDC_DispWord(80,16,&WLib_Num_8x16[tp%10*16],2,8,1);
break;
default:
break;
}
ENABLE_INTERRUPTS; //显示完毕,开中断
}
}
}
编译结果
通过编写程序,编译后在LCD 上显示出了电压和温度值,并且通过调节电位器能够看到电压值变化。
包括:定时器中断、A/D转换及中断和LCD显示。
五、实验结果分析
通过调节电位器,改变输入的模拟电压值,可以看到显示的通道0的电压随之发生变化,温度也随之发生微小变化。当电压升高时,温度随之变大。这里只对ADC0的通道0进行实验,通道1没有进行硬件连接,因而通道1的示数几乎不随电位器发生改变。可显示的电压为范围为:0~3V。程序中还使其可显示微小负电压。因此,程序完成了实验任务的要求。
通过本实验,掌握了C8051单片机A/D转换和时钟中断的程序设计方法。
实验五 D/A转换实验
一、实验时间及地点
电信学院西1楼,2011年12月4日
二、实验目的
掌握C8051单片机D/A转换程序设计方法
三、实验任务
设计并调试一个D/A采样程序,使用外部22.1184MHz 晶振。开机显示"西安交通大学"信息,为待机界面。定义'A'-'F'为功能键。按"A" 键,输出250HZ 的方波,按"B" 键,输出250HZ 的正弦波形,按"C" 键,输出250HZ 的三角波,按"D" 键,输出250HZ 的锯齿波。按”E”键调整输出波形的频率,每按一次输出波形的频率增加50HZ。波形最大频率为400HZ。当达到400HZ后,再按一次“E”键,波形频率减少50HZ。“F”键返回开机显示界面。用示波器在J6(DAC0)观测结果,使用串口观测按键信息。
四、实验原理
C8051F020有2个片内12位电压输出的数/模转换器(DAC)模块。每个DAC的输出百富均为0V~(VREF-1LSB),对应的输入范围是0x000~0xFFF。
DAC可设置为12位或8位方式。在12位分辨率时,应在写入DAC0L之后,再写DAC0H。在8为方式,将DAC0L初始化为一个所期望的数值(同常为0x00),只将数据写入DAC0H。
1. 波形输出
由各个子函数完成对应波形任一时刻输出电压值的计算。如计算正弦波的子函数为:
void sine(void)
{
unsigned int data y;
unsigned int data i;
for(i=0;i<256;i++)
{
y=sin(3.1415*2*i/256)*2048+2048;
if (y>4095)
y=4095;
TABLE[i]=y; }}
在本实验中,使用Timer4作为更新调度程序,即Timer4中断时调用DA转换,输出某一时刻的电压值。连续输出各个时刻的电压值就出现了波形。
2. 频率调节
由上述可知,调节Timer4的定时时间常数,即改变定时中断的频率,波形输出的频率就会对应地发生改变。通过计算50Hz对应的是计时时间常数约为69。
判断键值为”E”,则调整频率,程序如下:
case 0x0e:
i=65536-691+j*691/10;
j++;
if(j>5)
{j=j-2; }
Timer4_Init(i);
break;
3. 实现串口DA转换
设计并调试一个A/D采样程序,使用外部22.1184MHz 晶振。
展开阅读全文