串口控制器

1. 串口通信

1.1 什么是串口

是一种通信方式(通信协议) 主要通过串行方式完成设备间的数据通信

通信领域中使用最频繁,实现方式最简单的一种通信方式

串口: 全双工串行异步通信协议 

串口3线:  RX   接收 

  TX   发送

GND  共地信号   参考地  

1.1.1 通信

全双工,同时相互通信

半双工,不能同时但可以相互通信 

单工  ,只能从一方到另一方通信 

1.1.2 串行和并行

串行: 通过一根线传递数据, 按bit位方式 依次传递 使用的IO口少  传输较远  外设 

并行: 通过多根线传递数据, 单次可以传递多个bit 速度快  IO占用过多, 距离较近  

1.1.3 串口协议: 

 就是完成通信任务 约定的一种协议  

协议:  通信双方 约定的一些 规则  需要共同遵守 以完成通信 

1.2 电平的类别   

TTL电平:  +3v 表示1   0v 与gnd电压相同 数字0 

RS232电平:  +12/+5V表示0  -5/-12 表示1 

差分电平:  D+   D-     D+ > D- 表示 1  反之就表示0 

网线  USB  485 

抗干扰能力强 

1.3 波特率

通信双方约定 的 数据传输的速度  单位bps  bit每秒 

例如9600   115200   38400  .... 

1.4 同步通信和异步通信

异步通信:通信双方使用 自己独立 的时钟    对时操作

uart(串口 串行全双工异步协议 ) 

485       串行半双工异步协议 

同步通信: 通信双方使用 共同 的时钟

主机(主设备)(掌握时钟的一方)

从机(从设备)

IIC(串行半双工同步协议)  spi通信 (串行全双工同步协议) 

1.6 知识点

字长:  单次连续传输的 有效数据位数 

启停位: 开始传输 以及 结束传输时  用 1bit / 2bit的时间来对时 同步 

校验: 用于判断通信数据是否正确的 一种手段 

奇偶校验   CRC校验   md5检验 

纠错校验:  发送的数据中 不仅有有效数据 还报包含纠错数据  

流控:  流量控制 

硬件:   CTS RTS

软件:  

2. 串口通信实验

2.1 看原理图

1. 设备  

串口    A9板子 -----   (usb转串口)PC

2. 看电路图 

串口控制器_第1张图片

PC (usb转串口)  ---- CON7 ---- SP3232EEA(RS232电平转TTL电平3.3v)  ----- 

ALVC164245DGG(电压转换信息3.3v-1.8v)   ------ 1.8V TTL ------ GPA1_0 GPA1_1

2.2 串口控制器 

  芯片手册   1381页  28章

专门用于 实现串口通信协议的 一种硬件设备 

原理结构 如图 Figure 28-1 Block Diagram of UART  1384页 

串口控制器_第2张图片

2.3  寄存器

串口寄存器大部分都不需要我们配置,具体看手册

1396页 参考示例程序 

配置GPIO  GPA1_0和 GPA1_1 为串口功能 

2.3.1 下面是几个比较重要的寄存器

UTRSTATn 串口状态寄存器  

[2]  == 1  当发送数据寄存器为空  移位寄存器也空 自动设置1 

[1]  == 1  当发送数据寄存器为空 自动设置1   可以放一下个要发送的数据了

[0]  == 1  表示 串口接收到 一个字节数据 在 rxbuf中 

要发送和接收数据直接往这两个寄存器中仍或者读取就行了

UTXHn 发送数据寄存器  [7:0] 

URXHn 接收数据寄存器  [7:0]

波特率配置:  计算公式如下 

当波特率为115200 bps  

实际 总线时钟  100 MHz

总线时钟如下  446页

串口控制器_第3张图片

公式

DIV_VAL = (100M/(115200 * 16)) – 1

    = 53.25

串口控制器_第4张图片

UBRDIV2 [15:0] 波特率 有关  = 53  (公式求出的值的整数部分)

UFRACVALn [3:0] = 4 (小数部分程16后的结果)

2.4 写程序

uart_test------main

#include "exynos_4412.h"

//串口通信
void  uart_init()
{
    //配置GPA1_0和GPA1_1为串口功能
    //[7:4] = 0x2,[3:0]=0x2 ====>[7:0]=0x22
    GPA1.CON = GPA1.CON & ~(0xff<<0) |(0x22<<0);

    //配置串口控制器
    //ULCON寄存器
    //红外模式[6]=0   ,  校验[5:3]=0  ,  停止位[2]=0  , 字长 [1:0]=3
    UART2.ULCON2 = 3;  //0011

    //设置串口工作模式
    //UCON2  发送模式[3:2]=1   接收模式[1:0]=1
    UART2.UCON2 = 5;   //0101

    //波特率配置
    UART2.UBRDIV2 = 53;
    UART2.UFRACVAL2 = 4;

}

//发送一个字节
void putc(char c){
    //UTXH2 发送数据寄存器

    //等待上一个数据发送完成
    //如果UTRSTAT2 中的 1号bit 为1 证明为空,可以发送数据 为0 证明上一个数据还在发就需要阻塞在while
    // while(!(UART2.UTRSTAT2 & (1<<1)));
    while(((UART2.UTRSTAT2>>1) & 0x1)==0);
    UART2.UTXH2 = c;
}
//发送字符串
void puts(char* s){
    while(*s){
        putc(*s++);
    }
}

//接收一个数据
char getc(){
    //等待数据 如果UTRSTAT2 中的0号bit 为1 证明接收到数据 为0就是没接收到
    // while(!(UART2.UTRSTAT2 & (1<<0)));
    while(((UART2.UTRSTAT2>>0) & 0x1)==0);

    //因为URXH2是32位的寄存器 而我们设置的返回值char只有8位,所以通过[ & 0xff ]操作只保留低8位
    return UART2.URXH2 & 0xff;//返回接受的数据
}

int main()
{
    char c;
    uart_init();
    //发送
    puts("hello world\n");

    while(1){
        //接收数据
        c = getc();
        putc(c);
    }
    return 0;
}

串口控制器_第5张图片

3. printf移植: 

模板参考

E:\peixunQianrushi\jiekoubiancheng\笔记\程序模板

串口控制器_第6张图片

3.1 参考示例 

串口控制器_第7张图片

因为我们没有c库,所以用不了printf,所以在这个参考程序中printf被重写了,但是这个printf的功能是写入串口

printf----main.c

#include"exynos_4412.h"
#include"uart.h"


int main()
{
    int a = 100;
    uart_init();
    //这里是发送到串口
    printf("hello!a=%d\r\n",a);
    while(1);
    return 0;
}

串口控制器_第8张图片

4. 使用串口 发送数据  控制LED 亮灭 

例如: n   亮 

  f  灭 

4.1 写法一  

uart_led3-----uart.h

/*************************************************************************
	> File Name: uart.h
	> Author: 
	> Mail: 
	> Created Time: 2018年01月23日 09时44分27秒 HKT
 ************************************************************************/

#ifndef _UART_H
#define _UART_H

void uart_init(void);
void putc(char c);
void puts(const char *p);
char getc();

#endif

uart_led3-----uart.c

/*************************************************************************
	> File Name: uart.c
	> Author: 
	> Mail: 
    > Created Time: 2018年01月23日 09时42分13秒 HKT
 ************************************************************************/

#include"exynos_4412.h"
#include"uart.h"

void uart_init(void)
{
    //引脚功能配置
        //使能引脚为串口功能
    GPA1.CON = (GPA1.CON & ~0xff) | 0x22; 

    //串口控制器配置
        //设置字长,校验,停止位
    UART2.ULCON2 = 0x03;
        //设置串口工作模式
    UART2.UCON2  = 0x05;
        //设置串口波特率 115200
    UART2.UBRDIV2 = 53;
    UART2.UFRACVAL2 = 4;
}

void putc(char c)
{
    while(!(UART2.UTRSTAT2 & 0x02));
    UART2.UTXH2 = c;
}

void puts(const char *p)
{
    while(*p != '\0')
    putc(*p++);
}

//接收一个数据
char getc(){
    //等待数据 如果UTRSTAT2 中的0号bit 为1 证明接收到数据 为0就是没接收到
    while(((UART2.UTRSTAT2>>0) & 0x1)==0);

    //因为URXH2是32位的寄存器 而我们设置的返回值char只有8位,所以通过[ & 0xff ]操作只保留低8位
    return UART2.URXH2 & 0xff;//返回接受的数据
}




uart_led3-----main.c


#include"exynos_4412.h"
#include"uart.h"

//初始化led3
void led3_init()
{
    //配置引脚模式
    GPX1.CON = (GPX1.CON & ~(0xf<<0)) | (0x1 << 0);
    //配置数据寄存器
    // GPX1.DAT |= 1;
    GPX1.DAT &= ~1;
    //配置上下拉寄存器
    GPX1.PUD &= ~(0x3<<0);
}

int main()
{
    //初始化串口
    uart_init();
    //初始化led3
    led3_init();

    while(1){
        char str = getc();
        printf("%c",str);
        if(str == 'n'){//打开
            GPX1.DAT |= 1;
        }else if(str == 'f'){
            GPX1.DAT &= ~1;
        }
    }
    return 0;
}


串口控制器_第9张图片

4.2 写法二

uart_led-----main

写的不全主要看个思路


#include "exynos_4412.h"

void uart_init()
{
	//1.配置GPA1_0 GPA1_1 为对应串口功能
	//[7:4] =0x2 [3:0] = 0x2 ===>  [7:0] = 0X22
	GPA1.CON = (GPA1.CON &~ (0XFF << 0)) | ( 0X22<< 0);
	//2.配置 串口控制器
	//ULCONn [6] = 0,[5:3] = 0,[2] = 0,[1:0] = 3
	UART2.ULCON2 = 3;
	//UCON2 [5] = 0,[4] =0,[3:2] = 1,[1:0] = 1
	UART2.UCON2 = 5;
	//波特率配置
	UART2.UBRDIV2 = 53;
	UART2.UFRACVAL2 = 4;
}

void putc(char c)
{
	//等待上一个数据发送完成
	while( ! (UART2.UTRSTAT2 & (1<<1)) );
	UART2.UTXH2 = c;
}

void puts(char *s)
{
	while(*s) putc(*s++);
}

//接收一个字符
char getc()
{
	//等待数据到来
	while( ! (UART2.UTRSTAT2 & 1) );
	return UART2.URXH2 & 0XFF;
}

//接收一行 接收结束条件1.buf满了 2. '\n'
int gets(char *buf, int size)
{
	int len = 0;
	if(buf == (char *)0 || size <= 1) return -1;
	while(size - 1)
	{
		buf[len] = getc();
		putc(buf[len]); //回显
		len ++, size --;
		if(buf[len-1] == '\r') break;
	}
	//添加结束符号'\0'
	buf[len] = '\0';
	return len;
}


int strncmp(const char *s1,const char *s2, int len)
{
	int ret = 0;
	while(len--)
	{
		ret = *s1++ - *s2++;
		if(ret) return ret;
	}
	return 0;
}



int main()
{
	//char c;
	char buf[100];
	int len = 0;
	uart_init();
	puts("hello world\n");
	while(1)
	{
	//	c = getc();
	//	putc(c);
		len = gets(buf,sizeof(buf) - 1);
		if(len >= 5  && strncmp(buf,"LEDON",5) == 0)
		{//亮LED
			//...
			puts("ledon ok!\n");
		}
	}
    return 0;
}

你可能感兴趣的:(exynos4412接口编程,单片机,arm开发,嵌入式硬件)