arm串口实验.docx
《arm串口实验.docx》由会员分享,可在线阅读,更多相关《arm串口实验.docx(11页珍藏版)》请在冰豆网上搜索。
![arm串口实验.docx](https://file1.bdocx.com/fileroot1/2022-11/25/86ce8cd5-033d-4669-91d0-66fac5db89b6/86ce8cd5-033d-4669-91d0-66fac5db89b61.gif)
arm串口实验
嵌入式系统与微处理器B实验报告
ARM的串行口实验
一、实验目的
通过实验了解ARM处理器串行口(UART)的结构,串行通讯的原理。
掌握ARM处理器串行通信的编程方法。
二、实验内容
学习串行通讯原理,了解串行通讯控制器,阅读ARM芯片文档,掌握ARM的UART相关寄存器的功能,熟悉ARM系统硬件的UART相关接口。
编程实现ARM和计算机实现串行通讯:
ARM监视串行口,将接收到的字符再发送给串口(计算机与开发板是通过超级终端通讯的),即按PC键盘通过超级终端发送数据,开发板将接收到的数据再返送给PC,在超级终端上显示。
三、实验原理
S3C2410自带三个异步串行口控制器
每个控制器有16字节的FIFO(先入先出寄存器)
最大波特率115.2K
每个UART有7种状态:
溢出错误,校验错误,帧错误,暂停态,接收缓冲区准备好,发送缓冲区空,发送移位缓冲器空,这些状态可以由相应的UTRSTATn或UERSTATn寄存器表示,并且与发送接收缓冲区相对应的有错误缓冲区
波特率的大小可以通过设置波特率寄存器(UBRDIVn)控制,计算公式如下:
使用PCLK时的计算公式如下:
UBRDIVn=(int)[PCLK/(波特率×16)]–1
使用UCLK时的计算公式如下:
UBRDIVn=(int)[UCLK/(波特率×16)]–1
Ø例如:
使用PCLK,在40MHz的情况下,当波特率取115200bps时,
UBRDIVn=(int)[40000000/(115200×16)]–1=20
RS232接口电路
在本实验中,串口电路如下图所示,开发板上提供两个串口DB9。
其中UART0为主串口,可与PC或MODOM进行串行通迅
串行通信接口电路组成
Ø可编程的串行接口芯片
Ø波特率发生器
ØEIA与TTL电平转换器
Ø地址译码电路
通信协议:
Ø异步协议
Ø同步协议
开始前,线路处于空闲状态,送出连续“1”。
传送开始时首先发一个“0”作为起始位,然后出现在通信线上的是字符的二进制编码数据。
每个字符的数据位长可以约定为5位、6位、7位或8位,一般采用ASCII编码。
后面是奇偶校验位,根据约定,用奇偶校验位将所传字符中为“1”的位数凑成奇数个或偶数个。
也可以约定不要奇偶校验,这样就取消奇偶校验位。
最后是表示停止位的“1”信号,这个停止位可以约定持续1位、1.5位或2位的时间宽度。
至此一个字符传送完毕,线路又进入空闲,持续为“1”。
经过一段随机的时间后,下一个字符开始传送才又发出起始位。
每一个数据位的宽度等于传送波特率的倒数。
微机异步串行通信中,常用的波特率为110,150,300,600,1200,2400,4800,9600等。
四、实验步骤
1.准备实验环境。
使用简易JTAG仿真器连接目标板,使用UP2410实验板附带的串口线连接实验板上的UART0和PC机的串口。
2.在PC机上运行windows自带的串口通信程序超级终端程序,或者其它串口通信程序(如:
串口精灵等。
超级终端配置如下图所示)。
3.使用EmbestIDE通过Embest仿真器连接实验板,打开实验例程目录下例程,下载并运行它。
4.在PC上观察超级终端程序主窗口;
5.通过PC机键盘输入字符,可以看到相应的字符显示在超级终端主窗口,输入回车,所有字符一次性回显出来。
6.修改程序,要求键盘输入为“0”-“9”时,实验箱通过串口返回“9”-“0”,当输入为“A”-“Z”时,实验箱通过串口返回“a”-“z”,反之亦然。
7.重新编程采用中断方式实现串口驱动。
8.尝试将实验一和实验四结合起来,实现通过键盘输入实现对电机转速、转向的控制,可以通过按键来控制电机的关停和加速及减速。
五、程序说明
typedefstruct{//uart用一个结构体定义,因为三个uart口设置差不多
serial_init_func_tinit;
serial_read_func_tread;
serial_write_func_twrite;
serial_poll_func_tpoll;//查询
serial_flush_input_func_tflush_input;//流输入
serial_flush_output_func_tflush_output;//流输出
intnIsr;//中断号
}serial_driver_t;
intUart_Init(intwhichUart,intbaud)//初始化串口,选择第几个串口
{
if(whichUart>=NumberOfUartDrv)
returnFALSE;
returnserial_drv[whichUart]->init(baud);//返回给结构体中,对应的串口
}
intUart_SendByte(intwhichUart,intdata)
{
if(whichUart>=NumberOfUartDrv)
returnFALSE;
returnserial_drv[whichUart]->write(data);//发数据,一个字节
}
voidUart_SendString(intwhichUart,char*pt)
{//发数据流
while(*pt){//将pt指向的数据流发送出来
if(*pt=='\n')
Uart_SendByte(whichUart,'\r');
Uart_SendByte(whichUart,*pt++);
}
}
voidUart_Printf(intwhichUart,char*fmt,...)
{//在屏幕上打印
va_listap;
staticcharstring[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
Uart_SendString(whichUart,string);
va_end(ap);
}
charUart_Getchn(char*Revdata,intUartnum,inttimeout)
{//接受字符
if(Uartnum==0){
while(!
(rUTRSTAT0&0x1));//Receivedataread
*Revdata=RdURXH0();//把接受的字符给定义的指针字符串
returnTRUE;
}
elseif(Uartnum==1){
while(!
(rUTRSTAT1&0x1));//Receivedataread
*Revdata=RdURXH1();
returnTRUE;
}
else{
while(!
(rUTRSTAT2&0x1));//Receivedataread
*Revdata=RdURXH2();
returnTRUE;
}
}
//***********************************************************************
voidinit_MotorPort()
{rGPBCON=rGPBCON&0x3ffff0|0xa;
//DeadZone=24,PreScalero1=2;
rTCFG0=(0<<16)|2;//设置timer0作为pwm输出口,设置死区电压
//dividertimer0=1/2;
rTCFG1=0;
rTCNTB0=MOTOR_CONT;//定时器计数寄存器
rTCMPB0=MOTOR_MID;//定时器比较寄存器
rTCON=0x2;//updatemodeforTCNTB0andTCMPB0.
rTCON=0x19;//timer0=autoreload,start.DeadZone
}
voidSetPWM(intvalue)
{
rTCMPB0=MOTOR_MID+value;//通过给rTCMPB0不同的值,使输出口的pwm产生不//同的脉冲调制信号,控制电机转动。
}
六、关键源代码注释
根据实验目的和实验内容的要求,要求对其中主要的源代码给出详细的注释和说明。
并附主要的源代码。
修改程序,要求键盘输入为“0”-“9”时,实验箱通过串口返回“9”-“0”,当输入“A”-“Z”时,实验箱通过串口返回“a”-“z”,反之亦然。
intmyUart_SendByre(intwhichUart,intdata)
{
if(whichUart>=NumberOfUartDrv)
returnFALSE;
if(data<='9'&&data>='0')
{//输入0-9输出9-0
if(data>'5')data='5'-(data-'5');
elseif(data<'5')data='5'+('5'-data);
elsedata='5';
}
elseif(data>='a'&&data<='z')
{
data=data-32;
}
elseif(data>='A'&&data<='Z')
{
data=data+32;
}
returnserial_drv[whichUart]->write(data);
}
重新编程采用中断方式实现串口驱动。
voidmyUart_Init()
{
inti;
rGPHCON&=~(0xff);//useGPHportasuart0
rGPHCON|=
(2)|(2<<2)|(2<<4)|(2<<6);
rGPHUP=(0x0f);//thepullupfunctionisdisabled
rULCON0|=(3<<0);
//normal,noparity,onestopbit,8bit
rUCON0=0x05;//|=(1<<10)|(1<<6)|(1<<2)|(1<<0);;
rUFCON0=0x00;
rUMCON0=0x00;
rUBRDIV0=26;
//for(i=100;i>0;i--);
}
voidmyUart_int_init()
{
pISR_UART0=(unsignedint)uart0_receive;//串口收中断函数
rINTMOD&=~(1<<28);//所用中断都是IRQ
rINTMSK&=~(1<<28);//bit28isuart0//开按键和串口的中断
rINTSUBMSK&=~((1<<1)|(1<<0));//bit0isrx_int开串口收的中断
}
__irqvoiduart0_receive()
{
/*unsignedcharrec[2];//定义一个接受区,
rec[1]='\0';//后一个存结束符,便于发送。
rec[0]=rURXH0;//放在第一个
uart0_print(rec);//发送回去
//注意要先清楚子中断源,不然会产生两次中断,
//关于原因,请参考我写的关于中断的文章,明天写,稍等啊
ClearSubPending(BIT_SUB_RXD0);
ClearPending(BIT_UART0);//清除中断标志SRCPND
uart0_print(alp);*/
//uart0_print(buf_send);
rINTMSK|=(1<<28);
if(rUTRSTAT0&0x01)
{
unsignedcharrec[2];//定义一个接受区,
rec[1]='\0';//后一个存结束符,便于发送。
rec[0]=rURXH0;//放在第一个
//uart0_print(rec);//发送回去
rUTXH0=rec[0];
ClearSubPending(BIT_SUB_RXD0);
ClearPending(BIT_UART0);//清除中断标志SRCPND
rINTMSK&=~(1<<28);
return;
}
if(!
(rUTRSTAT0&0x02))
{
//uart0_print(buf_send);
while(!
(rUTRSTAT0&0x02));
//uart0_print(buf_send);
ClearSubPending(BIT_SUB_TXD0);
ClearPending(BIT_UART0);
rINTMSK&=~(1<<28);
return;
}
}
尝试将实验一和实验四结合起来,实现通过键盘输入实现对电机转速、转向的控制,可以通过按键来控制电机的关停和加速及减速。
if((rUTRSTAT0&0x1))//有输入,则跳出
{
control=RdURXH0();
Uart_Printf(0,"\ninput:
%c",control);
if(control=='+')
{//如果+按下,则将clock加500
clock+=500;
if(clock>=6500)
clock=6500;
Uart_Printf(0,"nowthemotoristurning:
clockwise");
Uart_Printf(0,"thestandardofthespeedis%d!
",clock/500);
SetPWM(clock);//赋值给电机,电机根据输入值调整转速
}
elseif(control=='-')
{
clock-=500;
if(clock<=-6500)
clock=-6500;
Uart_Printf(0,"nowthemotoristurning:
anti-clockwise");
Uart_Printf(0,"thestandardofthespeedis%d!
",clock/500);
SetPWM(clock);
}
elseif(control=='1')
{//按下1的时候反转
if(clock>=0)turnfl=1;
elseturnfl=0;
clock=(-clock);
if(turnfl==1)
{
Uart_Printf(0,"nowthemotoristurning:
anti-clockwise");
Uart_Printf(0,"thestandardofthespeedis%d!
",clock/500);
}
else
{
Uart_Printf(0,"nowthemotoristurning:
clockwise");
Uart_Printf(0,"thestandardofthespeedis%d!
",clock/500);
}
SetPWM(clock);
}
elseif(control=='2')
{按下2的时候停止
clock=0;
Uart_Printf(0,"nowthemotorisstop!
");
Uart_Printf(0,"thestandardofthespeedis%d!
",clock/500);
SetPWM(0);//将0值赋值给电机
}
}
七、思考题
1.232串行通讯的数据格式是什么?
异步串行通信中的字符传送格式
2.串行通讯最少需要几根线,分别如何连接?
两根,
Rxd-txdtxd-rxd
3.ARM的串行口有几个,相应的寄存器是什么?
3个
线路控制寄存器ULCONn,控制寄存器UCONn,FIFO控制寄存器UFCONn
控制寄存器UMCONn,状态寄存器UTRSTAT,错误状态寄存器UERSTAT
FIFO状态寄存器UFSTAT,发送寄存器UTXH和接收寄存器URXH,发送寄存器UTXH接收寄存器URXH,波特率因子寄存器UBRDIV
4.例程中的波特率为多少,如何确定的?
115200
例如:
使用PCLK,在50MHz的情况下,当波特率取115200bps时,
UBRDIVn=(int)[40000000/(115200×16)]–1=26
5.怎样在本例程的基础上增加错误检测功能?
错误状态寄存器UERSTAT
6.在充分理解程序代码的基础上根据以上的流程图对例程程序进行详细的注释。
见五,六