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. 看电路图
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.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页
公式
DIV_VAL = (100M/(115200 * 16)) – 1
= 53.25
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;
}
3. printf移植:
模板参考
E:\peixunQianrushi\jiekoubiancheng\笔记\程序模板
3.1 参考示例
因为我们没有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;
}
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;
}
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;
}