串口驱动学习
0.串口驱动的使用方法
//定义一个时间
struct rt_event system_event;
#define SYS_EVENT_UART_RX_FINISH 0x00000001 /* UART receive data finish event */
/*串口接收回调函数 Receive data callback function */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
//有数据到来,通知读取数据
rt_event_send(&system_event, SYS_EVENT_UART_RX_FINISH);
return RT_EOK;
}
static void test1_thread_entry(void* parameter)
{
rt_device_t uart_dev;
uint8_t data[30] = {0};
uint8_t data1[30] = {0};
uint16_t i = 0;
uint16_t data_length = 0;
rt_uint32_t sys_event_recv = 0;
rt_err_t result = rt_event_init(&system_event, "event", RT_IPC_FLAG_FIFO);
//查找设备
uart_dev = rt_device_find("usart3");
//打开设备
rt_device_open(uart_dev, RT_DEVICE_FLAG_INT_RX);//打开接收
/* 注册一个数据接收回调函数*/
rt_device_set_rx_indicate(uart_dev, uart_input);
for(i=0;i<sizeof(data);i++)
{
data[i]=i+1;
}
if(RT_EOK == rt_device_open(uart_dev, RT_DEVICE_FLAG_INT_RX))//打开中断
{
//串口发送数据
rt_device_write(uart_dev, RT_NULL, data, sizeof(data));
}
while(1)
{
rt_thread_delay(50);
/* 等待数据到来事件 */
if(RT_EOK == rt_event_recv(&system_event, SYS_EVENT_UART_RX_FINISH, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 10, &sys_event_recv))
{
data_length = rt_device_read(uart_dev, RT_NULL, data1, RT_SERIAL_RB_BUFSZ);
rt_device_write(uart_dev, RT_NULL, data1, data_length);
}
}
}
串口驱动抽象层
1.串口配置
struct serial_configure
{
rt_uint32_t baud_rate;
rt_uint32_t data_bits :4;
rt_uint32_t stop_bits :2;
rt_uint32_t parity :2;
rt_uint32_t hardwareflow_control :2;
rt_uint32_t mode :2;
rt_uint32_t bufsz :16;
rt_uint32_t reserved :6;
};
2.串口抽象操作
/**
* uart operators
*/
struct rt_uart_ops
{
//配置函数
rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
//控制函数
rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
//发送一个字符
int (*putc)(struct rt_serial_device *serial, char c);
//接收一个字符
int (*getc)(struct rt_serial_device *serial);
//dma数据发送
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
};
3.串口驱动抽象
struct rt_serial_device
{
struct rt_device parent;//RTT设备驱动抽象
const struct rt_uart_ops *ops;//串口抽象层操作函数
struct serial_configure config;//串口配置
void *serial_rx;
void *serial_tx;
};
typedef struct rt_serial_device rt_serial_t;
串口驱动硬件层
这个结构体封装N32L40x相关的串口硬件参数
struct n32l40x_uart
{
USART_Module* uart_periph; // Todo: 3bits串口号
IRQn_Type irqn; // Todo: 7bits 串口中断号
uint32_t per_clk; // Todo: 5bits串口时钟
uint32_t tx_gpio_clk; // Todo: 5bits发送引脚时钟
uint32_t rx_gpio_clk; // Todo: 5bits接收引脚时钟
GPIO_Module* tx_port; // Todo: 4bits发送引脚分gpio分组
uint32_t tx_af; // Todo: 4bits发送引脚的复用
uint16_t tx_pin; // Todo: 4bits发送引脚pin
GPIO_Module* rx_port; // Todo: 4bits接收引脚分gpio分组
uint32_t rx_af; // Todo: 4bits接收引脚的复用
uint16_t rx_pin; // Todo: 4bits接收引脚pin
struct rt_serial_device * serial; //串口驱动抽象父类
char *device_name; //串口名字
};
分析已经有的串口设备驱动程序
- 定义一个串口配置函数
- 定义一个串口控制函数
- 定义一个串口的单字符发送函数
- 定义一个串口的单字符接收函数
- 定义一个统一的串口中断处理函数
- 在同一的串口处理函数内部,清楚中断标志后,调用父类的中断处理函数 rt_hw_serial_isr
- 定义一个struct rt_uart_ops 对象分别赋值内部的,configure,control,putc,getc,dma_transmit(dma发送非必须)
- 注册串口设备对象 rt_hw_serial_register
如何自己添加或更改一个串口设备
文件在drv_usart.c 文件中修改