linux裸机串口,裸机系列-UART串口

下面我们就给出如何用s3c2440来实现非FIFO的UART通信。要实现某种通信,就必须遵循该通信协议。UART的协议包括传输数据的位数,停止位的位数,以及是否进行奇偶校验,这些设置是利用ULCONn寄存器完成的。另一个很重要的地方就是设置波特率。s3c2440波特率的时钟源有三个:PCLK、FCLK/n和UEXTCLK。时钟源的选择是由UCONn的第10位和第11位来完成的。波特率的具体计算公式为:

时钟源频率÷(波特率×16)-1

这个计算结果很可能是小数,把该小数取最接近的整数,放入寄存器UBRDIVn中就完成了波特率的设置。如我们选择波特率的时钟源为PCLK,它为50MHz,我们设置的波特率为115.2kHz,通过上式计算的结果为26.13,取整后得到26,那么我们把26放入UBRDIVn中即可。由于我们没有使用FIFO和MODEM,所以可以不用设置FIFO控制寄存器UFCONn和MODEM控制寄存器UMCONn。通过以上寄存器的设置,UART就可以正常传输数据。

接收到的数据是放到接收缓存器URXHn中,要发送数据时,是把数据放入发送缓存器UTXHn中。由于UART是通过字节方式传输数据的,因此要区分是大端模式还是小端模式,也就是说这两个寄存器在这两种模式下,所在的地址是不同。为了了解当前数据传输的各种状态,还需要一些状态寄存器。传输状态寄存器UTRSTATn非常有用,它的第0位可以用来判断接受缓存器内是否有可接收的数据,第1位和第2位可以用来判断发送缓存器中是否为空,为空时可以发送数据。由于在这里我们不进行传输数据时错误的判断,因此错误状态寄存器UERSTATn不需要,FIFO状态寄存器UFSTATn和MODEM状态寄存器UMSTATn在这里也不需要。

我们给出UART通信的两种方法:查询和中断。为了验证程序,使用任一款的串行通信软件来实现PC和s3c2440之间的通信即可。

首先给出的是查询程序。它是在主程序的循环体内不断查询UART端口,当有数据来时,就接收数据,并再通过UART发送该数据。然后根据所接收数据的不同,分别执行不同的内容,如点亮、熄灭LED,蜂鸣器响、或不响。在这里,我们每次只完成一个字节的传输。

#define rGPBCON    (*(volatile unsigned *)0x56000010)      //Port B control

#define rGPBDAT    (*(volatile unsigned *)0x56000014)       //Port B data

#define rGPBUP     (*(volatile unsigned *)0x56000018) //Pull-up control B

#define rGPHCON    (*(volatile unsigned *)0x56000070)      //Port H control

#define rGPHUP     (*(volatile unsigned *)0x56000078)       //Pull-up control H

#define rULCON0     (*(volatile unsigned *)0x50000000)     //UART 0 Line control

#define rUCON0      (*(volatile unsigned *)0x50000004)     //UART 0 Control

#define rUFCON0     (*(volatile unsigned *)0x50000008)     //UART 0 FIFO control

#define rUMCON0     (*(volatile unsigned *)0x5000000c)    //UART 0 Modem control

#define rUTRSTAT0   (*(volatile unsigned *)0x50000010)      //UART 0 Tx/Rx status

#define rUERSTAT0   (*(volatile unsigned *)0x50000014)      //UART 0 Rx error status

#define rUFSTAT0    (*(volatile unsigned *)0x50000018)      //UART 0 FIFO status

#define rUMSTAT0    (*(volatile unsigned *)0x5000001c)      //UART 0 Modem status

#define rUBRDIV0    (*(volatile unsigned *)0x50000028)     //UART 0 Baud rate divisor

//little endian

#define rUTXH0 (*(volatile unsigned char *)0x50000020) //UART 0 Transmission Hold

#define rURXH0 (*(volatile unsigned char *)0x50000024) //UART 0 Receive buffer

void Main(void)

{

char ch;

rGPBCON = 0x015551;

rGPBUP  = 0x7ff;

rGPBDAT = 0x1e0;

rGPHCON = 0x00faaa;                //使用UART0功能

rGPHUP  = 0x7ff;

rULCON0 = 0x3;             //设置UART0无奇偶校验,一位停止位,8位数据

rUCON0 = 0x245;         //PCLK为时钟源,接收和发送数据为查询或中断方式

rUFCON0 = 0;                     //

rUMCON0 = 0;                    //

rUBRDIV0 = 26;       //设置波特率,PCLK为50MHz,波特率为115.2kHz

while(!(rUTRSTAT0 & 0x2));       //等待并判断发送缓存是否为空

rUTXH0 = 0xaa;                         //是空,则发送0xAA字节

while(1)

{

while(!(rUTRSTAT0 & 0x1)); //等待并判断接收缓存是否准备好

ch = rURXH0;                     //接收一个字节数据

while(!(rUTRSTAT0 & 0x2));      //等待并判断发送缓存是否为空

rUTXH0 = ch;                     //发送一个字节数据

switch(ch)             //根据所接收数据的不同,执行不同的程序

{

case 0x11:              //灭LED

rGPBDAT |= 0x1e0;

break;

case 0x22:             //亮LED

rGPBDAT &= 0x1f;

break;

case 0x33:             //蜂鸣器不响

rGPBDAT &= 0x1e0;

break;

case 0x44:             //蜂鸣器响

rGPBDAT |= 0x1;

break;

default:                 //LED灭,蜂鸣器不响

rGPBDAT = 0x1e0;

break;

}

}

}

下面是UART中断程序,它要比查询复杂一些,因为涉及到了中断处理,并且UART发送数据和接收数据是一个中断源。主程序循环体内不执行任何程序,都在UART中断程序内执行。当接收到0x55字节数据时,亮两个LED,当接收到其他数据时,发送该字节,并在发送部分执行亮4个LED程序。

#define _ISR_STARTADDRESS 0x33ffff00

#define pISR_UART0           (*(unsigned *)(_ISR_STARTADDRESS+0x90))

#define U32 unsigned int

#define rGPBCON    (*(volatile unsigned *)0x56000010)      //Port B control

#define rGPBDAT    (*(volatile unsigned *)0x56000014)       //Port B data

#define rGPBUP     (*(volatile unsigned *)0x56000018) //Pull-up control B

#define rGPHCON    (*(volatile unsigned *)0x56000070)      //Port H control

//#define rGPHDAT    (*(volatile unsigned *)0x56000074)     //Port H data

#define rGPHUP     (*(volatile unsigned *)0x56000078)       //Pull-up control H

#define rULCON0     (*(volatile unsigned *)0x50000000)     //UART 0 Line control

#define rUCON0      (*(volatile unsigned *)0x50000004)     //UART 0 Control

#define rUFCON0     (*(volatile unsigned *)0x50000008)     //UART 0 FIFO control

#define rUMCON0     (*(volatile unsigned *)0x5000000c)    //UART 0 Modem control

#define rUTRSTAT0   (*(volatile unsigned *)0x50000010)      //UART 0 Tx/Rx status

#define rUERSTAT0   (*(volatile unsigned *)0x50000014)      //UART 0 Rx error status

#define rUFSTAT0    (*(volatile unsigned *)0x50000018)      //UART 0 FIFO status

#define rUMSTAT0    (*(volatile unsigned *)0x5000001c)      //UART 0 Modem status

#define rUBRDIV0    (*(volatile unsigned *)0x50000028)     //UART 0 Baud rate divisor

//little endian

#define rUTXH0 (*(volatile unsigned char *)0x50000020) //UART 0 Transmission Hold

#define rURXH0 (*(volatile unsigned char *)0x50000024) //UART 0 Receive buffer

#define rSRCPND     (*(volatile unsigned *)0x4a000000)     //Interrupt request status

#define rINTMSK     (*(volatile unsigned *)0x4a000008)      //Interrupt mask control

#define rINTPND     (*(volatile unsigned *)0x4a000010)      //Interrupt request status

#define rSUBSRCPND  (*(volatile unsigned *)0x4a000018)    //Sub source pending

#define rINTSUBMSK  (*(volatile unsigned *)0x4a00001c)    //Interrupt sub mask

void __irq uartISP(void)

{

char ch;

rSUBSRCPND |= 0x3;

rSRCPND = 0x1<<28;

rINTPND = 0x1<<28;

if(rUTRSTAT0 & 1)             //接收数据处理部分

{

ch = rURXH0;                     //接收字节数据

if(ch==0x55)

rGPBDAT = ~0x61;       //亮两个LED

else

rUTXH0 = ch;                     //发送字节数据

}

else               //发送数据处理部分

{

rGPBDAT = ~0x1e1;            //亮4个LED

}

}

void Main(void)

{

rGPBCON = 0x015551;

rGPBUP  = 0x7ff;

rGPBDAT = 0x1e0;

rGPHCON = 0x00faaa;

rGPHUP  = 0x7ff;

rULCON0 = 0x3;

rUCON0 = 0x5;

rUFCON0 = 0;

rUMCON0 = 0;

rUBRDIV0 = 26;

rSRCPND = 0x1<<28;

rSUBSRCPND = 0x3;

rINTPND = 0x1<<28;

rINTSUBMSK = ~(0x3);             //打开UART0发送和接收中断屏蔽

rINTMSK = ~(0x1<<28);            //打开UART0中断屏蔽

pISR_UART0 = (U32)uartISP;

while(1)

{

}

}

最后还要强调几点关于非FIFO模式下UART中断的一些注意事项:

1.对于s3c2440来说,接收数据是被动的,发送数据是主动的,因此一般来说,接收数据用中断方式,发送数据用查询方式较好;

2.在中断方式下,当接收到数据时,尽管可能该数据无用,但也一定要读取它,否则下次再接收数据时,不会再引起中断,因为接收数据缓存器被上次接收到的数据所霸占,只要没有读取它,它就永远在那里;

3.由于UART中断涉及到SUBSRCPND寄存器,因此在中断处理程序中不仅要清SRCPND寄存器,还要清SUBSRCPND寄存器,它们的顺序一定是先清SUBSRCPND寄存器,再清SRCPND寄存器,否则就会引起一个中断两次响应的问题。因为是否中断由SRCPND寄存器决定,而SRCPND寄存器的相关状态位由SUBSRCPND寄存器决定,如果先清SRCPND寄存器,而还没有清SUBSRCPND寄存器的话,SRCPND寄存器的相关位还是会被置1,而一旦被置1,则一定还会引起中断。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值