SCI 模块应用笔记(1)
UART,也就是异步串行通讯接口是单片机中最常见的外设,几乎每种类型的单片机都必备1到2个UART 接口,9S12 系列单片机也不例外。不过,摩托罗拉给他自己的单片机的串口起了个很有个性的缩写名称SCI (serial communication interface),其实就是我们常说的 UART。
各种单片机串口的编程都大同小异,无非就是设置波特率、起始位、停止位、校验位等等。下面通过给出编程例子的方式分别介绍。
设置波特率
/**
* Set the Baud Rate of the SCI.
* @param port, port can be SCI0 / SCI1
* @param baudRate, the wanted baud rate.
* @param busClk, The SCI module clock.
*/
void SCISetBaudRate (unsigned char port, unsigned long baudRate, unsigned long busClk)
{
unsigned short baudRateReg;
baudRateReg = (unsigned short) (busClk / baudRate / 16);
if (port == SCI0)
{
// Here we must write BDH first!
SCI0BDH = ( 0x1f & (baudRateReg >> 8) );
SCI0BDL = (0xff & baudRateReg);
}
else if(port == SCI1)
{
SCI1BDH = ( 0x1f & (baudRateReg >> 8) );
SCI1BDL = (0xff & baudRateReg);
}
else
{
// Something must go wrong. Do nothing here!
}
}
设置奇偶校验位
/**
* Enable/Disable parity function and set the Parity type
* @param port port can be SCI0 / SCI1
* @param isEnable 0 for disable parity function, 1 for enable
* @param type 0 for Even Parity, 1 for Odd Parity
*/
void SCISetParity (unsigned char port, unsigned char isEnable, unsigned char type)
{
if (port == SCI0)
{
SCI0CR1_PE = (isEnable & 0x01);
SCI0CR1_PT = (type & 0x01);
}
else if(port == SCI1)
{
SCI1CR1_PE = (isEnable & 0x01);
SCI1CR1_PT = (type & 0x01);
}
else
{
// If code run here, something must go wrong. Do nothing here!
}
}
使能数据位的长度
/**
* Set the Data Format Mode Bit
* @param port port can be SCI0 / SCI1
* @param bits must be 8 or 9
*/
void SCISetDataBit (unsigned char port, unsigned char bits)
{
if (port == SCI0)
{
switch(bits)
{
case 8:
SCI0CR1_M = 0; /* 1 start bit, 8 data bits, 1 stop bit */
break;
case 9:
SCI0CR1_M = 1; /* 1 start bit, 9 data bits, 1 stop bit */
break;
default:
// If code run here, something must go wrong. Do nothing here!
break;
}
}
else if(port == SCI1)
{
switch(bits)
{
case 8:
SCI1CR1_M = 0; /* 1 start bit, 8 data bits, 1 stop bit */
break;
case 9:
SCI1CR1_M = 1; /* 1 start bit, 9 data bits, 1 stop bit */
break;
default:
// If code run here, something must go wrong. Do nothing here!
break;
}
}
else
{
// If code run here, something must go wrong. Do nothing here!
}
}
设置串口的工作模式
NORMAL_MODE 是我们通常用的模式
LOOP_MODE 是自发自收模式
SING_WIRE_MODE 就是收发公用一条数据线的模式
/**
* Set the work mode of operation
* @param port port can be SCI0 / SCI1
* @param mode mode can be NORMAL_MODE / LOOP_MODE / SING_WIRE_MODE
*/
void SCISetWorkMode (unsigned char port, unsigned char mode)
{
if (port == SCI0)
{
switch(mode)
{
case NORMAL_MODE:
SCI0CR1_LOOPS = 0;
SCI0CR1_RSRC = 0;
break;
case LOOP_MODE:
SCI0CR1_LOOPS = 1;
SCI0CR1_RSRC = 0;
break;
case SING_WIRE_MODE:
SCI0CR1_LOOPS = 1;
SCI0CR1_RSRC = 1;
break;
default:
// If code run here, something must go wrong. Do nothing here!
break;
}
}
else if(port == SCI1)
{
switch(mode)
{
case NORMAL_MODE:
SCI1CR1_LOOPS = 0;
SCI1CR1_RSRC = 0;
break;
case LOOP_MODE:
SCI1CR1_LOOPS = 1;
SCI1CR1_RSRC = 0;
break;
case SING_WIRE_MODE:
SCI1CR1_LOOPS = 1;
SCI1CR1_RSRC = 1;
break;
default:
// If code run here, something must go wrong. Do nothing here!
break;
}
}
else
{
// If code run here, something must go wrong. Do nothing here!
}
}
设置SCI模块是否在Wait 模式下工作
/**
* Enable/Disable the SCI in wait mode
* @param port port can be SCI0 / SCI1
* @param mode mode can be RUN_MODE / WAIT_MODE
*/
void SCISetPowerMode (unsigned char port, unsigned char mode)
{
if (port == SCI0)
{
switch(mode)
{
case RUN_MODE:
SCI0CR1_SCISWAI = 0;
break;
case WAIT_MODE:
SCI0CR1_SCISWAI = 1;
break;
default:
// If code run here, something must go wrong. Do nothing here!
break;
}
}
else if(port == SCI1)
{
switch(mode)
{
case RUN_MODE:
SCI1CR1_SCISWAI = 0;
break;
case WAIT_MODE:
SCI1CR1_SCISWAI = 1;
break;
default:
// If code run here, something must go wrong. Do nothing here!
break;
}
}
else
{
// If code run here, something must go wrong. Do nothing here!
}
}
使能SCI模块的接收功能
/**
* Enable/Disable SCI Receiver
* @param port port can be SCI0 / SCI1
* @param isEnable 0 disable 1 enable
*/
void SCIEnableRecv (unsigned char port, unsigned char isEnable)
{
if (port == SCI0)
{
SCI0CR2_RE = (isEnable & 0x01);
}
else if(port == SCI1)
{
SCI1CR2_RE = (isEnable & 0x01);
}
else
{
// If code run here, something must go wrong. Do nothing here!
}
}
使能SCI模块的发送功能
/**
* Enable/Disable SCI Transmitter
* @param port port can be SCI0 / SCI1
* @param isEnable 0 disable 1 enable
*/
void SCIEnableTrans (unsigned char port, unsigned char isEnable)
{
if (port == SCI0)
{
SCI0CR2_TE = (isEnable & 0x01);
}
else if(port == SCI1)
{
SCI1CR2_TE = (isEnable & 0x01);
}
else
{
// If code run here, something must go wrong. Do nothing here!
}
}
发送数据
/**
* Send a char throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param s the data to be sent
*/
void SCIPutChar ( unsigned char port, unsigned char s)
{
if (port == SCI0)
{
while (SCI0SR1_TDRE == 0); // SCI0SR1_TC 是发送完成
SCI0DRL = s;
}
else
{
while (SCI1SR1_TDRE == 0); // SCI1SR1_TC
SCI1DRL = s;
}
}
/**
* Send a char string throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param *str the string to be sent
*/
void SCIPutStr (unsigned char port, unsigned char *str)
{
while (0 != *str)
{
SCIPutChar(port, *str);
str++;
}
}
/**
* Send data throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param *p pointer to the data to be sent
* @param size the size(byte) of the data
*/
void SCIWrite (unsigned char port, void *p, int size)
{
unsigned char *str = (unsigned char *)p;
while (size > 0)
{
SCIPutChar(port, *str);
str++;
size--;
}
}
/**
* Send a short int value(Big Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutShortBigEndian (unsigned char port, short i)
{
char * p = (char *)&i;
SCIPutChar( port, p[0]);
SCIPutChar( port, p[1]);
}
/**
* Send a short int value(Little Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutShortLittleEndian (unsigned char port, short i)
{
char * p = (char *)&i;
SCIPutChar( port, p[1]);
SCIPutChar( port, p[0]);
}
/**
* Send a long int value(Big Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutLongBigEndian (unsigned char port, long i)
{
char * p = (char *)&i;
SCIPutChar( port, p[0]);
SCIPutChar( port, p[1]);
SCIPutChar( port, p[2]);
SCIPutChar( port, p[3]);
}
/**
* Send a long int value(Little Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutLongLittleEndian (unsigned char port, long i)
{
char * p = (char *)&i;
SCIPutChar( port, p[3]);
SCIPutChar( port, p[2]);
SCIPutChar( port, p[1]);
SCIPutChar( port, p[0]);
}
接收数据
/**
* Receive a char data from SCI module,no reply.
* @param port port can be SCI0 / SCI1
* @return the received char
*/
unsigned char SCIGetChar(unsigned char port)
{
if (port == SCI0)
{
while( SCI0SR1_RDRF == 0);
return SCI0DRL;
}
else
{
while( SCI1SR1_RDRF == 0);
return SCI1DRL;
}
}
相应的头文件
/**
* file sci.h
* author Li Yuan
* platform: mc9s12dp256B
* date: 2012-4-16
* version: 1.0.0
* description: SCI(Serial Communication Interface) Support Code
*/
#ifndef _SCI_H_
#define _SCI_H_
#define SCI0 0
#define SCI1 1
#define IDLE_LINE 0
#define ADDRESS_MARK 1
#define NORMAL_MODE 0
#define LOOP_MODE 1
#define SING_WIRE_MODE 2
#define RUN_MODE 0
#define WAIT_MODE 1
/* Function Declaration */
/**
* Set the Baud Rate of the SCI.
* @param port, port can be SCI0 / SCI1
* @param baudRate, the wanted baud rate.
* @param busClk, The SCI module clock.
*/
void SCISetBaudRate(unsigned char port, unsigned long baudRate, unsigned long busClk);
/**
* Set the Interrupt Enable Bit
* @param port port can be SCI0 / SCI1
* @param tie Transmitter Interrupt Enable BIt
* @param tcie Transmission Complete Interrupt Enable BIt
* @param rie Receiver Full Interrupt Enable BIt
* @param ilie Idle Line Interrupt Enable BIt
* 0 Interrupt requests Disabled
* 1 Interrupt requests Enabled
*/
void SCISetIEBit(unsigned char port, unsigned char tie, unsigned char tcie, unsigned char rie, unsigned char ilie);
/**
* Enable The Tx interrupt (Transmitter Interrupt Enable BIt)
* @param port, port can be SCI0 / SCI1
*/
void SCIEnableTxInt(unsigned char port);
/**
* Disable The Tx interrupt (Transmitter Interrupt Enable BIt)
* @param port, port can be SCI0 / SCI1
*/
void SCIDisTxInt(unsigned char port);
/**
* Enable/Disable SCI Receiver
* @param port port can be SCI0 / SCI1
* @param isEnable 0 disable 1 enable
*/
void SCIEnableRecv(unsigned char port, unsigned char isEnable);
/**
* Enable/Disable SCI Transmitter
* @param port port can be SCI0 / SCI1
* @param isEnable 0 disable 1 enable
*/
void SCIEnableTrans(unsigned char port, unsigned char isEnable);
/**
* Set the Idle Line Type
* @param port port can be SCI0 / SCI1
* @param type 0 Idle char bit count begins after start bit
* 1 Idle char bit count begins after stop bit
*/
void SCISetIdleLineType(unsigned char port, unsigned char type);
/**
* Set the Wakeup Condition.
* @param port port can be SCI0 / SCI1
* @param condi 0 for Idle line wakeup, 1 for address mark wakeup
*/
void SCISetWakeupCondi(unsigned char port, unsigned char condi);
/**
* Enable/Disable parity function and set the Parity type
* @param port port can be SCI0 / SCI1
* @param isEnable 0 for disable parity function, 1 for enable
* @param type 0 for Even Parity, 1 for Odd Parity
*/
void SCISetParity(unsigned char port, unsigned char isEnable, unsigned char type);
/**
* Set the Data Format Mode Bit
* @param port port can be SCI0 / SCI1
* @param bits must be 8 or 9
*/
void SCISetDataBit(unsigned char port, unsigned char bits);
/**
* Set the work mode of operation
* @param port port can be SCI0 / SCI1
* @param mode mode can be NORMAL_MODE / LOOP_MODE / SING_WIRE_MODE
*/
void SCISetWorkMode(unsigned char port, unsigned char mode);
/**
* Enable/Disable the SCI in wait mode
* @param port port can be SCI0 / SCI1
* @param mode mode can be RUN_MODE / WAIT_MODE
*/
void SCISetPowerMode(unsigned char port, unsigned char mode);
/**
* Set the TXDIR ( Only for Single Wire MODE)
* @param port port can be SCI0 / SCI1
* @param dir 0 TXD used as input, 1 TXD used as output
*/
void SCISetTXDIR(unsigned char port, unsigned char dir);
/**
* Send a char throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param s the data to be sent
*/
void SCIPutChar( unsigned char port, unsigned char s);
/**
* Receive a char data from SCI module,no reply.
* @param port port can be SCI0 / SCI1
* @return the received char
*/
unsigned char SCIGetChar(unsigned char port);
/**
* Send a short int value(Big Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutShortBigEndian (unsigned char port, short i);
/**
* Send a short int value(Little Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutShortLittleEndian (unsigned char port, short i);
/**
* Send a long int value(Big Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutLongBigEndian (unsigned char port, long i);
/**
* Send a long int value(Little Endian) throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param i the data to be sent
*/
void SCIPutLongLittleEndian (unsigned char port, long i);
/**
* Send a char string throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param *str the string to be sent
*/
void SCIPutStr(unsigned char port, unsigned char *str);
/**
* Send data throungh SCI module.
* @param port port can be SCI0 / SCI1
* @param *p pointer to the data to be sent
* @param size the size(byte) of the data
*/
void SCIWrite(unsigned char port, void *p, int size);
#endif
下面给个简单的例子
#include /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include "sci.h"
void main(void)
{
char C;
EnableInterrupts;
SCISetWorkMode(SCI0, NORMAL_MODE);
SCISetPowerMode(SCI0, RUN_MODE);
SCISetBaudRate(SCI0, 9600, 16384000L); // 16M Clock
SCISetDataBit(SCI0, 8);
SCISetParity(SCI0, 0, 0);
SCIEnableRecv(SCI0, 1);
SCIEnableTrans(SCI0, 1);
for(;;)
{
_FEED_COP(); /* feeds the dog */
C = SCIGetChar(SCI0);
SCIPutChar(SCI0, C);
} /* loop forever */
/* please make sure that you never leave main */
}
先写这么多,剩下的明天继续。下一篇笔记中将给出如何利用串口的收发中断和环形缓冲区来实现较为完善的串口驱动。