串行通信技术-模拟信号转换接口.docx
《串行通信技术-模拟信号转换接口.docx》由会员分享,可在线阅读,更多相关《串行通信技术-模拟信号转换接口.docx(15页珍藏版)》请在冰点文库上搜索。
微机原理与应用实验报告6
实验9 串行通信技术
实验10A 模拟信号转换接口
实验报告
实验九串行通信技术
一、实验目的
1.了解异步串行通信原理;
2.掌握MSP430异步串行通信模块及其编程方法;
二、实验任务
1.了解MSP430G2553实验板USB转串口的通信功能,掌握串口助手的使用
(1)利用PC机的串口助手程序控制串口,实现串口的自发自收功能
为实现PC串口的自发自收功能,须现将实验板上的扩展板去下,并将单片机板上的BRXD和BTXD用杜邦线进行短接,连接图如下所示:
由此可以实现PC串口的自收自发功能。
(2)思考题:
异步串行通信接口的收/发双方是怎么建立起通信的
首先在异步通信中,要求接收方和发送方具有相同的通信参数,即起始位、停止位、波特率等等。
在满足上面条件的情况下,发送方对于每一帧数据按照起始位数据位停止位的顺序进行发送,而接收方则一直处于接受状态,当检测到起始位低电平时,看是采集接下来发送方发送过来的数据,这样一帧数据(即一个字符)传送完毕,然后进行下一帧数据的接受。
这样两者之间就建立起了通信。
2.查询方式控制单片机通过板载USB转串口与PC机实现串行通信
(1)硬件连接图
(2)C语言程序
采用SMCLK=1.0MHz时,程序如下:
#include"io430.h"
#include"in430.h"
unsignedinti,j,done,count;
charstring[32];
voidUSCIA0_int();
voidCLOCK_int();
intmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
USCIA0_int();//通信设置
CLOCK_int();//时钟设置
while
(1)
{
done=0;
count=0;
for(i=0;i<32;i++)
{
while((IFG2&UCA0RXIFG)==0);//循环等待接受缓冲器满
string[i]=UCA0RXBUF;//读接受缓冲器并保存
if(string[i]=='@')//检测发送完毕信号@
{
done=1;//接受完毕信号
break;
}
}
count=i;
if(done==1)//检测接受完毕信号
{
for(j=0;j<=count;j++)
{
while((IFG2&UCA0TXIFG)==0);
UCA0TXBUF=string[j];
}
done=0;
}
}
}
voidUSCIA0_int()
{
UCA0CTL1|=UCSWRST;
P1SEL|=BIT1+BIT2;
P1SEL2|=BIT1+BIT2;//端口设置
UCA0CTL1|=UCSSEL_2+UCRXEIE;//时钟选择设置(SMCLK)
UCA0BR1=0;UCA0BR0=104;
UCA0MCTL=UCBRS_1;//波特率设置
UCA0CTL1&=~UCSWRST;
}
voidCLOCK_int()
{
if(CALBC1_1MHZ!
=0xff)//设置时钟为1MHz
{
BCSCTL1=CALBC1_1MHZ;//采用smclk1MHZ
DCOCTL=CALDCO_1MHZ;
}
}
其中SMCLK=1MHz,波特率采用的是9600,采用低频波特方式,则N=1000000/9600=104.1666…,故UCA0BR1=0,UCA0BR0=104,UCBRS=1;
当采用外部晶振时,时钟采用默认设置即可,程序如下:
#include"io430.h"
#include"in430.h"
unsignedinti,j,done,count;
charstring[32];
voidUSCIA0_int();
intmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
USCIA0_int();//通信设置
while
(1)
{
done=0;
count=0;
for(i=0;i<32;i++)
{
while((IFG2&UCA0RXIFG)==0);//循环等待接受缓冲器满
string[i]=UCA0RXBUF;//读接受缓冲器并保存
if(string[i]=='@')//检测发送完毕信号@
{
done=1;//接受完毕信号
break;
}
}
count=i;
if(done==1)//检测接受完毕信号
{
for(j=0;j<=count;j++)
{
while((IFG2&UCA0TXIFG)==0);
UCA0TXBUF=string[j];
}
done=0;
}
}
}
voidUSCIA0_int()
{
UCA0CTL1|=UCSWRST;
P1SEL|=BIT1+BIT2;
P1SEL2|=BIT1+BIT2;//端口设置
UCA0CTL1|=UCSSEL_1+UCRXEIE;//时钟选择设置(SMCLK)
UCA0BR1=0;UCA0BR0=3;
UCA0MCTL=UCBRS_3;//波特率设置
UCA0CTL1&=~UCSWRST;
}
也是采用了低频波特率方式,所以关于波特率设置的相关计算和上面是一样的。
(3)思考:
如果在两个单片机之间进行串行通信,应该如何设计连线和编程?
由于在上面的连线中将单片机上的P1.2和BRXD相连,P1.1和BTXD相连,所以若要在两个单片机之间进行通信,首先应该将两个单片机的P1.2和P1.1交叉相连,并根据上面的程序进行相同的关于端口和波特率相关的设置即可实现两个单片机之间的通信。
3.(提高)利用PC机RS232通信接口与单片机之间完成串行通信
(1)硬件连接图
在实验时,采用了将PC机的串口com1直接连接至MSP430F149的孔型D9连接器上,G2553单片机的输出引脚P1.1和P1.2分别与F149单片机上的URXD1和UTXD1相连接,连接图如下所示:
(2)C语言程序
当采用波特率9600bps、无校验、8位数据位、先低后高、一个停止位时,所采用的程序和任务2中相同,这里不再赘述。
当采用波特率38400bps、无校验、8位数据位、先低后高、一个停止位时,由于采用外部晶振已经不能够产生这样高的波特率,所以采用SMCK=1MHz的时钟,所采用的程序只需将任务二中关于时钟选择和时钟设置的相关部分进行修改即可,具体程序见下面所示:
#include"io430.h"
#include"in430.h"
unsignedinti,j,done,count;
charstring[32];
voidUSCIA0_int();
voidCLOCK_int();
intmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
USCIA0_int();
CLOCK_int();
while
(1)
{
done=0;
count=0;
for(i=0;i<32;i++)
{
while((IFG2&UCA0RXIFG)==0);//循环等待接受缓冲器满
string[i]=UCA0RXBUF;//读接受缓冲器并保存
if(string[i]=='@')//检测发送完毕信号@
{
done=1;//接受完毕信号
break;
}
}
count=i;
if(done==1)//检测接受完毕信号
{
for(j=0;j{
while((IFG2&UCA0TXIFG)==0);
UCA0TXBUF=string[j];
}
done=0;
}
}
}
voidUSCIA0_int()
{
UCA0CTL1|=UCSWRST;
P1SEL|=BIT1+BIT2;
P1SEL2|=BIT1+BIT2;//端口设置
UCA0CTL1|=UCSSEL_2+UCRXEIE;//时钟选择设置
UCA0BR1=0;UCA0BR0=1;//波特率设置
UCA0MCTL=UCBRF_10+UCBRS_0+UCOS16;
UCA0CTL1&=~UCSWRST;
}
voidCLOCK_int()
{
if(CALBC1_1MHZ!
=0xff)
{
BCSCTL1=CALBC1_1MHZ;//采用smclk1MHZ
DCOCTL=CALDCO_1MHZ;
}
}
(3)思考题:
设计单片机与PC机进行串行通信时,硬件设计有哪些需要注意的事项?
首先最基本的是,单片机和PC机上所选择的通信协议应该是一致的,然后可以选择多种路径,其中包括USB,串口等。
另外需要注意的是要统一两者之间的逻辑电平,如果电平不同,则需要在中间加入电平转换电路。
4.(提高)中断方式控制串行通信的收发
(1)硬件连接图
由于只是将接收和发送改为了中断实现,其他功能并没有改变,所以这里的硬件连接图和任务2中的是相同的,这里不再重复。
(2)C语言程序
#include"io430.h"
#include"in430.h"
unsignedinti,j,done,count;
charstring[32];
voidUSCIA0_int();
intmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
USCIA0_int();
i=0;
j=0;
done=0;
IE2|=UCA0RXIE;
_EINT();
while
(1)
{
if(done==1)
{
IE2|=UCA0TXIE;
}
else
{
IE2&=~UCA0TXIE;
}
}
}
voidUSCIA0_int()
{
UCA0CTL1|=UCSWRST;
P1SEL|=BIT1+BIT2;
P1SEL2|=BIT1+BIT2;//端口设置
UCA0CTL1|=UCSSEL_1+UCRXEIE;//时钟选择设置
UCA0BR1=0;UCA0BR0=3;//波特率设置
UCA0MCTL=UCBRS_3;
UCA0CTL1&=~UCSWRST;
}
#pragmavector=USCIAB0RX_VECTOR //接收中断子程
__interruptvoidUCA0RX_ISR()
{
string[i]=UCA0RXBUF;
if(string[i]=='@')
{
done=1;
count=i;
i=0;
}
i++;
}
#pragmavector=USCIAB0TX_VECTOR //发送中断子程
__interruptvoidUCA0TX_ISR()
{
if(j{
UCA0TXBUF=string[j];
j++;
}
else
{
done=0;
j=0;
}
}
(3)思考题:
发送中断的允许位是否可以一直处于打开(允许)状态?
为什么?
发送中断的允许位不能够一直处于打开状态,因为当发送缓冲器为空时,发送中断标志位就会被置位,向系统发出中断请求,从而转去执行发送中断子程。
而当无法送内容时和刚发送完内容后发送缓冲器都处于空的状态,若发送中断允许位一直打开,在没有接受完毕进入发送时就会不断地向系统发出中断请求,从而导致系统不能正常。
所以,发送中断允许为应该在接受完毕准备发送时打开,发送完毕后立即关闭。
三、实验中遇到的问题和解决办法
1. 在任务二中使用SMCLK完成通信时,最开始始终无法完成通信,后来发现是由于SMCLK的时钟频率并不是刚好的1MHz,所以后来通过利用示波器测量实际的频率,重新计算产生波特率的相关的参数解决了问题;
2. 对于利用中断完成任务二的要求中,起初无法完成通信,后来发现是中断中由于在赋值完一次之后,先使i进行了加1,然后才判断对应的字符是否是‘@’,所以单片机一直没有发送到PC机上内容。
实验十 模拟信号转换接口
一、实验目的
1. 了解模/数转换的工作原理,掌握MSP430单片机内ADC10模/数转换模块的控制和应用。
二、实验任务
1. 模/数转换器ADC10的编程控制
(1)硬件连接图
(2)程序设计思路
首先需要利用示波器测量单片机板上的Vcc的大小,确定数/模转换公式中的参考电压的取值。
在编程时,由于测量的是稳恒电压,所以ADC的一些设置采用默认值即可,通过几次采样得到的值进行平均减小误差,然后转换为模拟值,利用得到的结果跟2.2和2.8进行比较,然后通过比较结果控制L1灯的亮灭。
(3)C语言程序
#include"io430.h"
#include"in430.h"
unsignedbuffer[32];
unsignedinti,sum;
floatvin;
intmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
P1SEL&=~BIT1;
P1SEL2&=~BIT1;
P1DIR|=BIT1;
P1OUT|=BIT1; //P1.1设置为GPIO用来控制L1
ADC10AE0|=BIT0;//允许A0管脚模拟输入
ADC10CTL0&=~ENC;//禁止ADC10转换
ADC10CTL1|=INCH_0;//采样通道为A0
ADC10CTL0|=ADC10ON+ENC;//给内核供电允许转换
while
(1) //主循环
{
sum=0;
for(i=0;i<4;i++)
{
ADC10CTL0|=ADC10SC;//软件启用采样
while((ADC10CTL0&ADC10IFG)==0);
buffer[i]=ADC10MEM;
sum=sum+buffer[i];
}
vin=((sum/4)*3.5/1023); //通过公式计算出测量的电压值
if(vin>2.80)
{
P1OUT&=~BIT1;
}
if(vin<2.20)
{
P1OUT|=BIT1;
}
}
}
(4)思考题:
如果模拟信号从P1.5输入,应该如何编程?
若模拟信号从P1.5输入只需将允许管脚模拟输入和采样通道的选择进行修改即可,其他的不用改变。
并在硬件上使模拟信号从P1.5输入即可。
需要修改的指令如下所示:
ADC10AE0|=BIT0;//允许A0管脚模拟输入
ADC10CTL1|=INCH_0;//采样通道为A0
2. (提高)改用中断的方式实现任务1
(1)硬件连接图
硬件连接图任务一中相同,所以在这里不再给出。
(2)C语言程序
#include"io430.h"
#include"in430.h"
unsignedbuffer[32];
unsignedinti=0,sum;
floatvin;
intmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
P1SEL&=~BIT1;
P1SEL2&=~BIT1;
P1DIR|=BIT1;
P1OUT|=BIT1;
ADC10AE0|=BIT0;//允许A0管脚模拟输入
ADC10CTL0&=~ENC;//禁止ADC10转换
ADC10CTL1|=INCH_0;//采样通道为A0
ADC10CTL0|=ADC10ON+ENC;//给内核供电允许转换
ADC10CTL0|=ADC10IE;
_EINT(); //打开总控位
ADC10CTL0|=ADC10SC; //软件启动转换
sum=0;
while
(1)
{
if(vin>2.80)
{
P1OUT&=~BIT1;
}
if(vin<2.20)
{
P1OUT|=BIT1;
}
ADC10CTL0|=ADC10SC; //软件启动转换
}
}
#pragmavector=ADC10_VECTOR //中断子程
__interruptvoidADC10_ISR()
{
buffer[i]=ADC10MEM;
sum=sum+buffer[i];
i++;
if(i==4)
{
vin=((sum/4)*3.5/1023);
sum=0;
i=0;
}
}
3.(提高)制作数字电压表
(1)硬件连接图
(2)程序设计思路
其中最基本的任务和上面两个任务中完成方式相同,在这里需要改进的就是将测得的电压值进行数码管显示,只需要利用之前实验中设计的数码管显示模块就可以了。
(3)C语言程序
#include"io430.h"
#include"in430.h"
unsignedbuffer[32];
unsignedinti=0,sum;
unsignedcharNUM_tab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
intvin;
floatvin1;
voidseg(intnumber);
intmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
P1SEL&=~(BIT0+BIT1+BIT2+BIT3);
P1SEL2&=~(BIT0+BIT1+BIT2+BIT3);
P1DIR|=(BIT0+BIT1+BIT2+BIT3);
P2SEL=0;
P2SEL2=0;
P2DIR=0xff;
ADC10AE0|=BIT5;//允许A0管脚模拟输入(改为BIT5)
ADC10CTL0&=~ENC;//禁止ADC10转换
ADC10CTL1|=INCH_5;//采样通道为A0(改为INCH_5)
ADC10CTL0|=ADC10ON+ENC;//给内核供电允许转换
ADC10CTL0|=ADC10IE;
_EINT();
ADC10CTL0|=ADC10SC;
sum=0;
while
(1)
{
seg(vin);
ADC10CTL0|=ADC10SC;
}
}
#pragmavector=ADC10_VECTOR
__interruptvoidADC10_ISR()
{
buffer[i]=ADC10MEM;
sum=sum+buffer[i];
i++;
if(i==4)