芯片内置UART接口,用于与外部进行异步串行通信。串口控制器有如下特征:1,内置波特率发生器,支持不同波特率的配置;2,数据位宽支持5/7/8bit;3 停止位可配置成1或2bit;4,可支持38Khz红外调制;5 , 支持自动波特率检测。
-每个UART口,芯片会分配16K的地址。每个UART相关的寄存器如下图:
寄存器名称 | 作用 |
---|
uart_ctl | uart控制寄存器 |
uart_baud | uart波特率配置寄存器 |
uart_txd | uart发送数据寄存器 |
uart_rxd | uart接收数据寄存器 |
UART_CTRL寄存器的每个位的具体作用如下图:
uart_ctl 寄存器bit位 | 具体bit位作用 |
---|
bit0(EN) | 置1时模块使能 |
bit1(TXIN) | 置1时发送中断使能, 对应的是sta状态寄存器中的bit0) |
bit2(RXIN) | 置1时接收数据中断使能,对应sta状态寄存器中的bit1 |
bit3(ERRIN) | 置1时,打开错误中断使能,对应sta状态寄存器的bit2-bit5 |
bit4(STOPS) | 置1时,设置为2bit的停止位;置0时,表示1bit的停止位 |
bit6-5(data_translen) | 控制数据传输时的bit位; 00: 5bit;01: 6bit;10:7bit;11:8bit |
bit9-7(pars数据校验) | 000: 无校验;001:奇校验;010:偶校验;011:固定为0校验;100:固定为1校验 |
编写UART串口驱动程序时,需要从以下几个方面进行考虑。
- 串口时钟使能,GPIO时钟使能;
- 串口复位;
- GPIO端口模式配置;
- 串口参数初始化
- 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤);
- 使能串口;
- 编写中断处理函数。
//UART_rx口模式寄存器通过bitband映射到的地址
//UART_rx口数据寄存器通过bitband映射到的地址
//UART_tx口模式寄存器通过bitband映射到的地址
//UART_tx口数据寄存器通过bitband映射到的地址
#include <stdio.h>
#define UART_rxgpio_mode 0x50000000
#define UART_rxgpio_data 0x50000004
#define UART_txgpio_mode 0x50000008
#define UART_txgpio_data 0x5000000C
#define UART_rstgpio_mode 0x50000012
#define UART_rstgpio_data 0x50000016
//适合所有GPIO口的通用的数据结构
#define uart_num 3//设备中uart通道的总个数是3个。
struct gpio_t
{
int *gpio_data_out;//gpio数据寄存器,用来输出数据
int *gpio_data_in;//gpio数据寄存器,用来输入数据
int *gpio_mode; //gpio模式寄存器,用来控制io口是输入还是输出的。
void (*out_mode) (int *gpio_mode); //gpio配置为输出模式
void (*in_mode) (int *gpio_mode); //gpio配置为输入模式
void (*active_signal) (int *gpio_data_out); //gpio的数据寄存器中,某一位输出有效位(打开功能)
void (*non_active_signal) (int *gpio_data_out); //gpio的数据寄存器中,某一位输出无效位(关闭功能)
};
void out_mode (int *gpio_mode)
{
*gpio_mode = 1;//输入模式
}
void in_mode (int *gpio_mode)
{
*gpio_mode = 1;//输入模式
}
void active_signal (int *gpio_data_out)
{
*gpio_data_out = 1;//这个要根据实际情况,看高电平有效还是低电平有效
}
void non_active_signal (int *gpio_data_out)
{
*gpio_data_out = 0;//这个要根据实际情况,看高电平有效还是低电平有效
}
//一个UART口至少要包括TX和Rx,对于外设寄存器,芯片厂家一般会给出bitband,对数据和模式寄存器的地址进行映射到另外一片内存区域,进行位操作
struct gpio_t rx =
{
(int *)UART_rxgpio_data, //gpio通过bitband映射到的地址
(int *)UART_rxgpio_data, //gpio通过bitband映射到的地址
(int *)UART_rxgpio_mode,
out_mode,
in_mode,
active_signal,
non_active_signal,
};//uart的接收io口
struct gpio_t tx =
{
(int *)UART_txgpio_data, //gpio通过bitband映射到的地址
(int *)UART_txgpio_data, //gpio通过bitband映射到的地址
(int *)UART_txgpio_mode,
out_mode,
in_mode,
active_signal,
non_active_signal,
}; //uart的发送io口
struct gpio_t rst =
{
(int *)UART_rstgpio_data, //gpio通过bitband映射到的地址
(int *)UART_rstgpio_data, //gpio通过bitband映射到的地址
(int *)UART_rstgpio_mode,
out_mode,
in_mode,
active_signal,
non_active_signal,
}; //uart的复位的io口
//对uart进行数据结构的定义
struct uart_t
{
char *name;//分清是哪个串口
struct gpio_t *rx;
struct gpio_t *tx;
struct gpio_t *rst;
};
struct uart_t remote_uart =
{
"remote_uart",
(int *)&rx,
(int *)&tx,
(int *)&rst,
};
//串口相关的配置
struct uart_config_t
{
int baud_rate; //波特率的配置
int data_bits; //数据位
int parity; //奇偶校验位
int stop_bits; //停止位
int data_process_mode;//数据处理的方式,分为扫描和中断
};
enum data_process_mode
{
scan_mode = 0,//扫描的方式
invt_mode //中断的方式
};
struct uart_config_t uart_config =
{
9600,
8,//8位数据位
0,//无校验
1,//1位停止位
invt_mode,//中断的方式
};
//芯片内部总的全局变量,用来控制各个外设工作的。
struct sys_t
{
int osc_ctl1;//系统OSC控制寄存器
int sys_mode;//系统模式切换寄存器
int sys_pd; //系统掉电控制寄存器
int ADC_CTL; //ADC控制寄存器(电源控制)
int osc_ctl2;//系统osc2控制寄存器
int sys_rst; //系统复位寄存器
int map_ctl; //地址映射控制寄存器
int mode0_en;//模块使能0寄出器
int mode1_en;//模块使能1寄存器
int nvic_en; //nvic中断使能寄存器
int kbi_en; //kbi使能寄存器
};
struct sys_t sys;
struct uart_t_paramete_config_t
{
int ctrl;//控制寄存器
int baud;//波特率配置寄存器
int stat;//uart相关的状态寄存器
int txd;//发送数据寄存器
int rxd;//接收数据的寄存器
};
struct uart_t_paramete_config_t uart;
//串口的状态
struct uart_status_t
{
int reset_time_count;//达到这个固定的时间,就复位一下串口。防止串口彻底乱了
int tx_time_out;//每次发送完时间的延时,超过这个时间,才允许再次发送
int rx_time_out;//每次接收数据的时间延时计时。两帧之间只有大于这个时间,才允许继续读出来
};
struct uart_status_t uart_status[uart_num];
struct fifo_t
{
int *fifo_buf;//uart串口通信的起始地址
int rd; //读的指针
int wd; //写的指针
int buf_len;//uart串口总的数据长度
};
struct resource_driver_t;//编译这个参数时,会自动往下查找的。
struct device_t
{
int device_id;//器件对应的id
int trans_class;//总线传输类型:IIC,SPI,Uart
void *bus_driver;//总线驱动(万能的void*,后面进行实例化时,可以进行强转)
void *resource; //实际占用的硬件资源(IO等)
void *resource_cfg;//硬件资源的配置:如控制灯如何闪烁间隔等
struct resource_driver_t *resouce_driver;//器件资源控制驱动(初始化,读,写,控制的驱动)
};
//设备驱动的初始化,读,写,执行功能,需要用函数指针进行实例化
struct resource_driver_t
{
int (init*)(struct device_t *device,int mode);//根据上电,下电,复位等情况时,对资源进行初始化操作
int (*read)(int addr, int *buf, int len, struct device_t *device);//根据资源实际挂载的传输总线。进行查找里面的值
int (*write)(int addr, int *buf, int len, struct device_t *device);
int(*ioctrl)(int ctlid, struct device_t *device, int parameter);//根据传进来的参数进行实际控制设备
};
struct uart_buffer_t
{
struct fifo_t rx;//接收的缓存
struct fifo_t tx;//发送数据的缓存
struct device_t *device;//uart实际物理设备的地址
};
struct uart_buffer_t uart_buf[uart_num];
void nvic_disable(int uart_nvic_index)
{
}
void nvic_enable(int uart_nvic_index)
{
}
void uart_init (struct uart_config_t *uart_config, struct uart_t *remote_uart)
{
//在芯片的上配置对应的时钟使能
sys.mode0_en |= 1 << 5; //使能远程通信串口的时钟
//会根据配置的串口的数据位和校验位信息,进行改变ctrl里面寄存器的值
if (uart_config->data_bits == 8)
{
uart.ctrl |= (uart_config->data_bits - 5) << 5;//将ctrl的bit5,6进行置位。
}
uart.baud = uart_config->baud_rate; //暂时用这个方法,实际上比这个复杂,具体根据芯片厂家来确定
//根据配置的uart数据是扫描还是中断的方式,来确定系统的中断是否生效
if (uart_config->data_process_mode == scan_mode) //配置为扫描的方式,则uart对应的系统中断失效
{
nvic_disable(0); //远程uart中断号失效,不在使用
}
else
{
nvic_enable(0);//将uart口的中断号生效
}
}
int main()
{
struct gpio_t *txio = remote_uart.tx;
struct gpio_t *rst = remote_uart.rst;
memset(sys,0);
//uart的初始化,是在通信模块上电瞬间进行初始化的:根据实际的uart通道的个数,分别对每个uart进行初始化操作
//1.首先uart底层驱动的buffer指向应用层实际的串口。
//上电时,先设定好io口是输入还是输出的模式。输出模式时,模式寄存器对应的bit位为0;输入模式时,模式寄存器上对应的bit位为1
remote_uart.tx->out_mode(txio->gpio_mode);//将rx配置为输出模式,由于电脑上0x50000008这个内存不能分配给使用,故会报错。嵌入式硬件上可以
remote_uart.tx->out_mode(rst->gpio_mode);//将rst管脚配置为输出模式
//根据配置好的uart相关io配置及串口通信相关的配置,对串口进行初始化。主要功能:修改UART相关寄存器里面的值
uart_init(&uart_config, &remote_uart);
//上电过程中通过文件系统,进行读,写,控制串口通信
system("pause");
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)