目录
资料来自韦东山嵌入式
硬件介绍
通用异步收发器简称 UART,全双工方式传输数据,最精简的连线方法只有三根电线:TxD 用于发送数据,RxD 用于接收数据,Gnd 用于给双方提供参考电平。
连接方式:1. 2440使用TTL逻辑电平,而PC使用的是RS232电平,所以加入电平转换芯片将TTL转换为RS232与PC通信。
2. 2440外接USB串口芯片,通过USB接入PC。
数据包格式
数据传输流程:
(1)空闲为高电平
(2)当要发送数据时,UART 改变 TxD 数据线的状态(变为 0 状态)并维持 1 位的时间──这
样接收方检测到开始位后,再等待 1.5 位的时间就开始一位一位地检测数据线的状态得到所传输的数据。
(3)UART 一帧中可以有 5、6、7 或 8 位的数据,发送方一位一位地改变数据线的状态将它
们发送出去,首先发送最低位。
(4)如果使用较验功能,UART 在发送完数据位后,还要发送 1 个较验位。有两种较验方法:
奇较验、偶较验──数据位连同较验位中,“1”的数目等于奇数或偶数。
(5)最后,发送停止位,数据线恢复到“空闭”状态(1 状态)。停止位的长度有 3 种:1 位、
1.5 位、2 位。
波特率计算
假设波特率115200,8n1 (数据位8位,无奇偶校验,1位停止位)
每一位传输t=1/115200
传输1Byte需要10位(开始为,数据位,停止位)
则传输1Byte T=10/115200
则一秒可以传输:1/T=115200/10=11520 Byte
串口框架
串口中存在数据缓存FIFO,移位寄存器。发送数据时,CPU从内存中取得数据,放入FIFO,UART将FIFO中的数据通过移位寄存器一位一位发送出去。接收数据同理。
S3C2440_UART编程
修改007_clock
添加usrt.c
void urat0_init()
{
/*设置引脚用于串口 */
/*GPH2,3用于TxD0,RxD0*/
GPHCON &= ~((3<<4)|(3<<6));//清零
GPHCON |= (2<<4)|(2<<6);
GPHUP &= ~((1<<2)|(1<<3)); //设置GPH2,3引脚上拉
/*设置波特率
*UBRDIVn = (int) (UART clock / (buad rate x 16)) –1
* UART clock=50M //前面时钟章节设置的
* UBRDIVn = (int) (50 000 000 / (115200 x 16)) –1 =26
*/
UCON0=0x00000005; //设置UCON为PCLK,中断/查询模式
UBRDIV0=26;
/*设置数据格式*/
ULCON0=0x00000003; //无校验,1停止位 8位数据长度 8n1
/*其他设置*/
}
void putchar(int c)//输出字符
{
/*UTXH0 UART通道 0 发送缓存寄存器
*UTRSTAT0 UART通道 0 接收发送状态 寄存器
*/
while(!(UTRSTAT0 & (1<<2))); //等待发送器空
UTXH0 =(unsigned char)c; //写入一个字节
}
int getchar(void)
{
while(!(UTRSTAT0 & (1<<0))); //等待接收器有数据
return URXH0;
}
int puts(const char *s)//输出字符串
{
while(*s)
{
putchar(*s);
s++;
}
}
添加uart.h
#ifndef _UART_H
#define _UART_H
void urat0_init();
void putchar(int c);
int getchar(void);
int puts(const char *s);
#endif
添加main.c,输出helloworld,输出输入的字符
#include "s3c2440_soc.h"
#include "uart.h"
int main(void)
{
unsigned char c;
urat0_init();
puts("Hello,world\n");
while(1)
{
c=getchar();
if(c=='\r')//\r表示回到行首
{
putchar('\n');//\n表示提行
}
if(c=='\n')
{
putchar('\r');
}
putchar(c);
}
return 0;
}
修改makefile
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 start.o led.o uart.o main.o -o uart.elf
arm-linux-objcopy -O binary -S uart.elf uart.bin
arm-linux-objdump -D uart.elf > uart.dis
clean:
rm *.bin *.o *.elf *.dis
手动实现printf
手动实验可变参数
printf的输出格式:
格式字符 | 说明 |
d | 以带符号的十进制形式输出整数(整数不输出符号) |
u | 以无符号十进制形式输出整数 |
x | 以十六进制无符号形式输出整数(不输出前导符0x), 用x则输出十六进制数的a~f时以小写形式输出 |
c | 以字符形式输出,只输出一个字符 |
s | 输出字符串 |
printf在内存中的变量是以堆栈的方式存放的
如以下代码:
#include <stdio.h>
//int printf(const char *format, ...);
/*
* 打印出传入参数,format为第一个传入参数,...为可变参数
*/
int push_test(const char *format, ...)
{
char *p=(char *) &format;
int i;
/*(1)将abcd传入format,为了取得后面的数据123,定义一个指针指向format,通过指针移动读取*/
printf("arg1: %s\n",format);//abcd传入了第一个format
p=p+sizeof(char *);
i=*((int *)p);
printf("arg2:%d\n",i);
return 0;
}
int main(int argc,char **argv)
{
printf("sizeof(char )=%d\n",sizeof(char ));
printf("sizeof(int )=%d\n",sizeof(int ));
printf("sizeof(char *)=%d\n",sizeof(char *));
printf("sizeof(char **)=%d\n",sizeof(char **));
push_test("abcd",123); //(1)
return 0;
}
在内存中的表示为:
注意编译时 gcc -m32 -o push_test push_test.c
输出:
sizeof(char )=1
sizeof(int )=4
sizeof(char *)=4
sizeof(char **)=4
arg1: abcd
arg2:123
加入结构体观察:
#include <stdio.h>
struct person{
char *name;
int age;
char score;
int id;
};
//int printf(const char *format, ...);
/*
* 打印出传入参数,format为第一个传入参数,...为可变参数
*/
int push_test(const char *format, ...)
{
char *p=(char *) &format;
int i;
struct person per;
/*(1)将abcd传入format,为了取得后面的数据123,定义一个指针指向format,通过指针移动读取*/
printf("arg1: %s\n",format);//abcd传入了第一个format
p=p+sizeof(char *);
i=*((int *)p);
printf("arg2:%d\n",i);
/*传入结构体输出*/
p=p+sizeof(int);
per=*((struct person *)p);
printf("arg3: .name = %s, .age = %d, .socre=%c .id=%d\n",\
per.name, per.age, per.score, per.id);
return 0;
}
int main(int argc,char **argv)
{
struct person per={"www.100ask.org",10,'A',123};//
printf("sizeof(char )=%d\n",sizeof(char ));
printf("sizeof(int )=%d\n",sizeof(int ));
printf("sizeof(char *)=%d\n",sizeof(char *));
printf("sizeof(char **)=%d\n",sizeof(char **));
printf("sizeof(struct person)=%d\n",sizeof(struct person));
//push_test("abcd",123); //(1)
push_test("abcd",123,per);//(2)
return 0;
}
传入push_test可变参数结构体时,内存中的表示如下:
输出:
sizeof(char )=1
sizeof(int )=4
sizeof(char *)=4
sizeof(char **)=4
sizeof(struct person)=16
arg1: abcd
arg2:123
arg3: .name = www.100ask.org, .age = 10, .socre=A .id=123
由于在x86(32位机器)平台下,GCC编译器默认按4字节对齐,
如:结构体4字节对齐,即结构体成员变量所在的内存地址是4的整数倍。
字节对齐
可以通过使用gcc中的__attribute__选项来设置指定的对齐大小。
1):
__attribute__ ((packed)),让所作用的结构体取消在编译过程中的优化对齐,按照实际占用字节数进行对齐。
2):
__attribute((aligned (n))),让所作用的结构体成员对齐在n字节边界上。
如果结构体中有成员变量的字节长度大于n,则按照最大成员变量的字节长度来对齐。
#include <stdio.h>
/*
由于在x86(32位机器)平台下,GCC编译器默认按4字节对齐,
如:结构体4字节对齐,即结构体成员变量所在的内存地址是4的整数倍。
可以通过使用gcc中的__attribute__选项来设置指定的对齐大小。
1):
__attribute__ ((packed)),让所作用的结构体取消在编译过程中的优化对齐,
按照实际占用字节数进行对齐。
2):
__attribute((aligned (n))),让所作用的结构体成员对齐在n字节边界上。
如果结构体中有成员变量的字节长度大于n,
则按照最大成员变量的字节长度来对齐。
*/
struct person{
char *name;
int age;
char score;
int id;
};
struct person1{
char *name;
int age;
char score;
int id;
}__attribute__ ((packed));
struct person2{
char *name;
int age;
char score;
int id;
}__attribute((aligned (4)));
int main(int argc,char **argv)
{
struct person per={"www.100ask.org",10,'A',123};
printf("sizeof(char )=%d\n",sizeof(char ));
printf("sizeof(int )=%d\n",sizeof(int ));
printf("sizeof(char *)=%d\n",sizeof(char *));
printf("sizeof(char **)=%d\n",sizeof(char **));
printf("sizeof(struct person)=%d\n",sizeof(struct person));
printf("sizeof(struct person1)=%d\n",sizeof(struct person1));
printf("sizeof(struct person2)=%d\n",sizeof(struct person2));
printf("&per.name =%p,per.name =%s\n",&per.name ,per.name);
printf("&per.age =%p,per.age =%d\n",&per.age ,per.age);
printf("&per.score =%p,per.score =%d\n",&per.score,per.score);
printf("&per.id =%p,per.id =%d\n",&per.id ,per.id);
return 0;
}
输出:
sizeof(char )=1
sizeof(int )=4
sizeof(char *)=4
sizeof(char **)=4
sizeof(struct person)=16
sizeof(struct person1)=13
sizeof(struct person2)=16
&per.name =0xff8cbc9c,per.name =www.100ask.org
&per.age =0xff8cbca0,per.age =10
&per.score =0xff8cbca4,per.score =65
&per.id =0xff8cbca8,per.id =123
默认情况下的内存分布
自动确定可变参数
变参函数的使用:
将上述程序改为变参函数:
#include <stdio.h>
#include <stdarg.h>
struct person{
char *name;
int age;
char score;
int id;
};
//int printf(const char *format, ...);
/*
* 打印出传入参数,format为第一个传入参数,...为可变参数
*/
int push_test(const char *format, ...)
{
//char *p=(char *) &format;
int i;
struct person per;
va_list p;
/*(1)将abcd传入format,为了取得后面的数据123,定义一个指针指向format,通过指针移动读取*/
printf("arg1: %s\n",format);//abcd传入了第一个format
//p=p+sizeof(char *);
va_start(p, format );//移动指针p到第一个变参变量
//==============
/*指针对连续空间操作时: 1) 取值 2)移动指针*/
//i=*((int *)p);
//p=p+sizeof(int);
i = va_arg(p,int);//在已知int的情况下,返回p所指向的变参变量给i,并且移动指针p到下一个变量
printf("arg2:%d\n",i);
//==============
/*指针对连续空间操作时: 1) 取值 2)指针赋值空,避免野指针*/
/*传入结构体输出*/
//per=*((struct person *)p);
per = va_arg(p,struct person);
va_end( p );
printf("arg3: .name = %s, .age = %d, .socre=%c .id=%d\n",\
per.name, per.age, per.score, per.id);
return 0;
}
int main(int argc,char **argv)
{
struct person per={"www.100ask.org",10,'A',123};
printf("sizeof(char )=%d\n",sizeof(char ));
printf("sizeof(int )=%d\n",sizeof(int ));
printf("sizeof(char *)=%d\n",sizeof(char *));
printf("sizeof(char **)=%d\n",sizeof(char **));
printf("sizeof(struct person)=%d\n",sizeof(struct person));
//push_test("abcd",123); //(1)
push_test("abcd",123,per);//(2)
return 0;
}