帮人做毕设 查到的东西留个底儿:
Mini2440有三个串口,USRT0,UART1,UART3。
对串口的操作有三种:串口初始化,串口接收,串口发送
1 串口初始化
1)串口初始化函数
void Uart_Init(int pclk,int baud)
{
int i;
if(pclk == 0)
pclk = PCLK;
rUFCON0 = 0x0; //UART channel 0 FIFO control register, FIFO disable
rUFCON1 = 0x0; //UART channel 1 FIFO control register, FIFO disable
rUFCON2 = 0x0; //UART channel 2 FIFO control register, FIFO disable
rUMCON0 = 0x0; //UART chaneel 0 MODEM control register, AFC disable
rUMCON1 = 0x0; //UART chaneel 1 MODEM control register, AFC disable
//UART0
rULCON0 = 0x3; //Line control register : Normal,No parity,1 stop,8 bits
// [10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
// Clock Sel, Tx Int, Rx Int, Rx Time Out, Rx err, Loop-back, Send break, Transmit Mode, Receive Mode
// 0 1 0 , 0 1 0 0 , 01 01
// PCLK Level Pulse Disable Generate Normal Normal Interrupt or Polling
rUCON0 = 0x245; // Control register
rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 ); //Baud rate divisior register 0
//UART1
rULCON1 = 0x3;
rUCON1 = 0x245;
rUBRDIV1=( (int)(pclk/16./baud+0.5) -1 );
//UART2
rULCON2 = 0x3;
rUCON2 = 0x245;
rUBRDIV2=( (int)(pclk/16./baud+0.5) -1 );
for(i=0;i<100;i++);
}
l 串口时钟的设置
pclk = PCLK;使用PCLK作为串口的时钟。
l 寄存器进行了设置
主要是对三种寄存器进行了设置
rUFCONn (n=0,1,2) —— 串口FIFO控制寄存器
rUMCONn (n=0,1)——串口调制控制寄存器
rULCONn (n=0,1,2)——串口线性控制寄存器
rUCONn(n=0,1,2)——串口控制寄存器
rUBRDIVn(n=0,1,2)——串口Tx,Rx收发速率的设定
2)串口的选择
void Uart_Select(int ch)
{
whichUart = ch;
}
2 串口发送
串口发送数据通过判断rUTRSTATn (n=0,1,2)的第2位是不是为1来判断发送缓存是否为空。
1) 串口发送字节
void Uart_SendByte(int data)
{
if(whichUart==0)
{
if(data=='/n')
{
while(!(rUTRSTAT0 & 0x2));
// Delay(1); //because the slow response of hyper_terminal
WrUTXH0('/r');
}
while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty.
// Delay(1);
WrUTXH0(data);
}
else if(whichUart==1)
{
if(data=='/n')
{
while(!(rUTRSTAT1 & 0x2));
//Delay(1); //because the slow response of hyper_terminal
rUTXH1 = '/r';
}
while(!(rUTRSTAT1 & 0x2)); //Wait until THR is empty.
//Delay(1);
rUTXH1 = data;
}
else if(whichUart==2)
{
if(data=='/n')
{
while(!(rUTRSTAT2 & 0x2));
//Delay(1); //because the slow response of hyper_terminal
rUTXH2 = '/r';
}
while(!(rUTRSTAT2 & 0x2)); //Wait until THR is empty.
//Delay(1);
rUTXH2 = data;
}
}
首先是串口通道的选择;然后判断THR是否为空,直到等到发送缓存为空,退出while循环;再要发送的字节data放到发送缓存中。如果发送的数据是回车的话,直接发送转义字符/r,当然也要等到THR为空才可以发送。
2) 串口发送字符串
void Uart_SendString(char *pt)
{
while(*pt)
Uart_SendByte(*pt++);
}
把字符串看作是字符数组,字符指针*pt来指代字符数组的首地址,读取指针指向的字符,这样就可以把发送的的字符串逐个进行字节发送了。
2 串口接收
串口接收通过判断rUTRSTATn (n=0,1,2)的第1位是不是为1来判断发送缓存是否为空。
1)串口等待接收状态
void Uart_TxEmpty(int ch)
{
if(ch==0)
while(!(rUTRSTAT0 & 0x4)); //Wait until tx shifter is empty.
else if(ch==1)
while(!(rUTRSTAT1 & 0x4)); //Wait until tx shifter is empty.
else if(ch==2)
while(!(rUTRSTAT2 & 0x4)); //Wait until tx shifter is empty.
}
寄存器rUTRSTATn & 0x4 (n=0,1,2)来判断tx shifter是不是为空
3) 接收字符
char Uart_Getch(void)
{
if(whichUart==0)
{
while(!(rUTRSTAT0 & 0x1)); //Receive data ready
return RdURXH0();
}
else if(whichUart==1)
{
while(!(rUTRSTAT1 & 0x1)); //Receive data ready
return RdURXH1();
}
else if(whichUart==2)
{
while(!(rUTRSTAT2 & 0x1)); //Receive data ready
return RdURXH2();
}
return 0 ;
}
寄存器rUTRSTATn & 0x1 (n=0,1,2)来判断Receive data ready?并把接收到的数据写到接收缓存里面。
4) 接收字符串
void Uart_GetString(char *string)
{
char *string2 = string;
char c;
while((c = Uart_Getch())!='/r')
{
if(c=='/b')
{
if( (int)string2 < (int)string )
{
Uart_Printf("/b /b");
string--;
}
}
else
{
*string++ = c;
Uart_SendByte(c);
}
}
*string='/0';
Uart_SendByte('/n');
}
char Uart_GetKey(void)
{
if(whichUart==0)
{
if(rUTRSTAT0 & 0x1) //Receive data ready
return RdURXH0();
else
return 0;
}
else if(whichUart==1)
{
if(rUTRSTAT1 & 0x1) //Receive data ready
return RdURXH1();
else
return 0;
}
else if(whichUart==2)
{
if(rUTRSTAT2 & 0x1) //Receive data ready
return RdURXH2();
else
return 0;
}
return 0 ;
}
寄存器rUTRSTATn & 0x1 (n=0,1,2)
来判断Receive data ready?并把接收到的数据写到接收缓存里面。否则返回空。与getchar类似,并且也是返回字符类型。
5) 接收整形数字
函数返回类型:整形
int Uart_GetIntNum(void)
{
char str[30];
char *string = str;
int base = 10;
int minus = 0;
int result = 0;
int lastIndex;
int i;
Uart_GetString(string);
if(string[0]=='-')
{
minus = 1;
string++;
}
if(string[0]=='0' && (string[1]=='x' || string[1]=='X'))
{
base = 16;
string += 2;
}
lastIndex = strlen(string) - 1;
if(lastIndex<0)
return -1;
if(string[lastIndex]=='h' || string[lastIndex]=='H' )
{
base = 16;
string[lastIndex] = 0;
lastIndex--;
}
if(base==10)
{
result = atoi(string);
result = minus ? (-1*result):result;
}
else
{
for(i=0;i<=lastIndex;i++)
{
if(isalpha(string))
{
if(isupper(string))
result = (result<<4) + string - 'A' + 10;
else
result = (result<<4) + string - 'a' + 10;
}
else
result = (result<<4) + string - '0';
}
result = minus ? (-1*result):result;
}
return result;
}
首先以字符串的形式接收数据Uart_GetString(string);
然后通过判断是不是以‘-’开头来确定是不是负数,是负数则minus=1;再通过以0x,oX开头或者以H,h结尾来判断是不是16进制,否则为10进制;如果是10进制,则通过atoi把字符串转化为数字,并加上正负,如果是16进制,判断是不是字母,再判断大小写字母分别进行转换。16进制也支持正负号。
6) 接收10进制的数
int Uart_GetIntNum_GJ(void)
{
char string[16] ;
char *p_string = string ;
char c;
int i = 0 ;
int data = 0 ;
while( ( c = Uart_Getch()) != '/r' )
{
if(c=='/b') p_string--;
else *p_string++=c;
Uart_SendByte( c ) ;
}
*p_string = '/0';
i = 0 ;
while( string != '/0' )
{
data = data * 10 ;
if( string<'0'||string>'9' )
return -1 ;
data = data + ( string-'0' ) ;
i++ ;
}
return data ;
}
只转化10进制的数字。首先用getchar接收单个字符存储在string中,然后把string转换为整型的data。并返回整形的data。
3串口打印
//If you don't use vsprintf(), the code size is reduced very much.
void Uart_Printf(char *fmt,...)
{
va_list ap;
char string[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
Uart_SendString(string);
va_end(ap);
}
va_list完成可变参数的操作
具体实现如下
n 由于无法列出传递函数的所有实参的类型和数目时,用省略号指定参数表
void Uart_Printf(char *fmt,...)
n 函数参数的传递原理
函数参数是以数据结构:栈的形式存取,从右至左入栈.
n 获取省略号指定的参数
在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。
va_list ap;
char string[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
Uart_SendString(string);
va_end(ap);
va_start使ap指向第一个可选参数。va_end把ap指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。
vsprintf(string,fmt,ap);实现向字符数组中写指定格式的内容
=============================================================================
=============================================================================
硬件 mini2440核心板,自已画的底板,另外一块带串口的单片机学习板(挂着DS18B20),学习板连续输出DS18B20的温度值,波特率19200。
在一个文件夹里新建一个文件,我的是voltage_set.c(以后用来调压)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FALSE -1
#define TRUE 1
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, //
B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300,
38400, 19200, 9600, 4800, 2400, 1200, 300, };
void set_speed(int fd, int speed)
{
int i;
int status;
struct termios Opt;
tcgetattr(fd, &Opt);
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++)
{
if (speed == name_arr[i])
{
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0)
perror("tcsetattr fd1");
return;
}
tcflush(fd,TCIOFLUSH); //í¬éÏ
}
}
int set_Parity(int fd,int databits,int stopbits,int parity)
{
struct termios options; //¶¨òåò»¸ö½á11
if ( tcgetattr( fd,&options) != 0) //ê×Ïè¶áè¡Ïμí3ĬèÏéèÖÃoptionsÖD,±ØDë
{
perror("SetupSerial 1");
return(FALSE);
}
options.c_cflag &= ~CSIZE; //ÕaêÇéèÖÃc_cflagÑ¡Ïî2»°′λêy¾YλÑúÂë
switch (databits)
{
case 7:
options.c_cflag |= CS7; //éèÖÃc_cflagÑ¡Ïîêy¾YλÎa7λ
break;
case 8:
options.c_cflag |= CS8; //éèÖÃc_cflagÑ¡Ïîêy¾YλÎa8λ
break;
default:
fprintf(stderr,"Unsupported data size\n"); //ÆäËûμĶ¼2»Ö§3Ö
return (FALSE);
}
switch (parity) //éèÖÃÆæżD£Ñ飬c_cflagoíc_iflagóDD§
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 'o':
case 'O': options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK;
break;
case 'e':
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK;
break;
default:
fprintf(stderr,"Unsupported parity\n");
return (FALSE);
}
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return (FALSE);
}
if (parity != 'n')
options.c_iflag |= INPCK;
options.c_cc[VTIME] = 150; // 15 seconds
options.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}
int OpenDev(char *Dev)
{
int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAYÕaÖÖ·½ê½¿′openoˉêy
if (-1 == fd)
{
perror("Can't Open Serial Port");
return -1;
}
else
return fd;
}
int main(int argc, char **argv)
{
int fd;
int nread;
char buff[512];
char *dev ="/dev/ttySAC1";
fd = OpenDev(dev);
if (fd>0)
{
printf("Open Serial succeed\n");
set_speed(fd,19200);
}
else
{
printf("Can't Open Serial Port!\n");
exit(0);
}
if (set_Parity(fd,8,1,'N')== FALSE)
{
printf("Set Parity Error\n");
exit(1);
}
while(1)
{
int i;
// char buff1[2]={0x5a,0x5a};
// write(fd,buff1,1);
while((nread = read(fd,buff,512))>0)
{
printf("\nLen %d\n",nread);
buff[nread+1]='\0';
for(i=0;i printf("0x%x",buff[i]);
printf("\n");
}
}
//close(fd);
//exit(0);
}
完了之后arm-linux-gcc -o voltage_set voltage_set.c
生成voltage_set
下载到mini2440核心板中
执行#./voltage_set
把学习板的地与核心板的地相连,学习板的TX与核心板的RX2相连就可以看到温度值了,当然,我用16进制显示在超级终端上,关掉程序用ctrl+c
======================================================================================
======================================================================================
inux串口C程序,基于mini2440与TX2440A
5小时前 弄了好多天这个串口程序了,昨天晚上终于好了,现在把过程给贴出来 环境:Asinaux linux 2.6(其它系统也可以) 硬件环境:mini2440(linux2.6.29)或TX2440A(2.6.31) 编译器:arm-linux-gcc4.1.2 先献上程序:main.c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************* * 功 能:初始化串口 * 程序名称:int uart_init(int arg, int baud) * 参 数:arg: 串口号 baud: 波特率 * 返 回 值:成功:串口打开句柄 失败:返回 -1 * 创 建 人:ZB * 创建日期:07.05.08 * 版本更新 *******************************************************/ int uart_init(int arg, int baud) { int fd; char port[20]; struct termios Opt; int uartbiit[50]={B115200,B9600,B19200,B4800,B2400,B1200}; sprintf(port,"/dev/s3c2410_serial%d",arg); /*2.6.31内核的串口设备文件是/dev/s3c2410_serialX(X=0 1 2 或3), 在mini2440中/dev/ttySACX(X=0 1 2或3)不再是ttyS0,ttyS1,ttyS2*/ printf("port %s \n", port); fd = open(port, O_RDWR); //打开串口 if (fd<0) { return -1; //没有打开返回 } tcgetattr(fd,&Opt); //初始化 tcflush(fd,TCIFLUSH); cfsetispeed(&Opt,uartbiit[baud]); //设置波特率 cfsetospeed(&Opt,uartbiit[baud]); Opt.c_cflag |= CS8; //设置数据位 Opt.c_cflag &= ~PARENB; Opt.c_oflag &= ~(OPOST); Opt.c_cflag &= ~CSTOPB; Opt.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN); Opt.c_iflag &= ~(INPCK|BRKINT|ICRNL|ISTRIP|IXON); Opt.c_cc[VMIN] = 0; Opt.c_cc[VTIME] = 0; if (tcsetattr(fd,TCSANOW,&Opt) != 0) //装载初始化参数 { perror("SetupSerial!\n"); close(fd); return -1; } return(fd); } int main() { int fd, len = 0, i=0; char buf[20]; if((fd = uart_init(1, 0)) <0) //打开串口0,波特率为115200; { printf("Open uart err \n"); return -1; } sprintf(buf, "Hello world !\n"); //输出内容 for(;;) { sprintf(buf, "%d", i++); len = write(fd, buf, 1); //写串口 printf("Open uart err \n"); //为测试是不是运行到这里设的输出 if(len > 0) { read(fd, buf, sizeof(buf)); //读串口数据 printf("buf %s\n", buf); //输出读到的数据 } usleep(100000); } return 0; } 此时再编译下载到开发板运行,用windows串口和板子的串口连在一起,看一下是不是接收到数据了,是一直发的,并且一直累加, 以下是输出内容: port /dev/s3c2410_serial1 Open uart err buf 0 Open uart err buf 1 Open uart err buf 2 Open uart err buf 3 Open uart err buf 4 Open uart err buf 5 Open uart err buf 6 Open uart err buf 7 Open uart err buf 8 Open uart err buf 9 Open uart err buf 10 Open uart err buf 11 Open uart err buf 12 Open uart err buf 13 Open uart err buf 14 Open uart err buf 15 Open uart err buf 16 Open uart err buf 17 Open uart err buf 18 Open uart err buf 19 Open uart err buf 20 Open uart err buf 21 Open uart err buf 22 Open uart err buf 23 Open uart err buf 24 Open uart err buf 25 Open uart err buf 26 Open uart err buf 27 Open uart err buf 28 Open uart err buf 29 Open uart err buf 30 Open uart err buf 31 Open uart err buf 32 Open uart err buf 33 Open uart err buf 34 Open uart err buf 35 Open uart err buf 36 有用的话大家可以交流一下的,我QQ115424242或786298427
阅读(3277) | 评论(0) | 转发(1) |