NRF52832开发:普通串口驱动


本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.

 

环境:

开发环境:MDK5.23


说明:
编写NRF52832普通串口的驱动,发送是查询方式,接收采用中断方式。接收时每20ms处理一次。


源代码:

drv_uart.h

/**
* Copyright (c), 2015-2025
* @file drv_uart.h
* @brief 串口驱动层头文件
* @author jdh
* @email jdh821@163.com
* @date 2017/7/4
* @verbatim 
* 硬件连接说明
* 电路标号			单片机引脚			
* USART1_TX       	P0.08					
* USART1_RX       	P0.06				
* @endverbatim 
*/

#ifndef _DRV_UART_H_
#define _DRV_UART_H_

/*********************************************************************
*							头文件
**********************************************************************/

#include "stdint.h"

/*********************************************************************
*							宏定义
**********************************************************************/

/**
* @brief 波特率值
*/

#define BAUD1200					0x0004F000
#define BAUD2400					0x0009D000
#define BAUD4800					0x0013B000
#define BAUD9600					0x00275000
#define BAUD14400					0x003B000
#define BAUD19200					0x004EA000
#define BAUD28800					0x0075F000
#define BAUD38400					0x009D5000
#define BAUD57600					0x00EBF000
#define BAUD76800					0x013A9000
#define BAUD115200					0x01D7E000
#define BAUD230400					0x03AFB000
#define BAUD250000					0x04000000
#define BAUD460800					0x075F7000
#define BAUD921600					0x0EBED000
#define BAUD1M						0x10000000

/**
* @brief 默认的波特率
*/

#define DEFAULT_BAUD				BAUD1M

/**
* @brief IO口
*/

#define PIN_UART_TX					6
#define PIN_UART_RX					8

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 初始模块
*/

void drv_uart_init(void);

/**
* @brief 串口发送数据
* @param data:发送数据存放地址
* @param size:发送数据字节数
*/

void drv_uart_tx(uint8_t *data, uint16_t size);

/**
* @brief 处理接收完成中断
* @retval 接收到的字节
*/

uint8_t drv_uart_deal_irq_rx_end(void);

#endif



drv_uart.c

/**
* Copyright (c), 2015-2025
* @file drv_uart.c
* @brief 串口驱动层主文件
* @author jdh
* @email jdh821@163.com
* @date 2017/7/4
*/

/*********************************************************************
*							头文件
**********************************************************************/

#include "drv_uart.h"
#include "drv_gpio.h"
#include "nrf.h"
#include "drv_irq_priority.h"

/*********************************************************************
*							静态函数
**********************************************************************/

static void init_io(void);
static void init_uart(void);
static void enable_interrupt(void);

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 初始模块
*/

void drv_uart_init(void)
{	
	init_io();
	init_uart();
}

static void init_io(void)
{	
	drv_gpio_config_output(PIN_UART_TX);
	drv_gpio_set_high(PIN_UART_TX);
	drv_gpio_config_input(PIN_UART_RX, GPIO_NOPULL);
}

static void init_uart(void)
{
	NRF_UART0->BAUDRATE = DEFAULT_BAUD;
	
	NRF_UART0->PSELTXD = PIN_UART_TX;
	NRF_UART0->PSELRXD = PIN_UART_RX;
	
	enable_interrupt();
	// 使能串口
	NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled;
	NRF_UART0->TASKS_STARTTX = 1;
	NRF_UART0->TASKS_STARTRX = 1;
}

static void enable_interrupt(void)
{
	NRF_UART0->EVENTS_RXDRDY = 0;		
	NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos;
	
	NVIC_SetPriority(UART0_IRQn, IRQ_PRIORITY_LOW);
    NVIC_ClearPendingIRQ(UART0_IRQn);
    NVIC_EnableIRQ(UART0_IRQn);
}

/**
* @brief 串口发送数据
* @param data:发送数据存放地址
* @param size:发送数据字节数
*/

void drv_uart_tx(uint8_t *data, uint16_t size)
{
	for (int i = 0; i < size; i++)
	{
		NRF_UART0->TXD = data[i];
		while (NRF_UART0->EVENTS_TXDRDY == 0);
		NRF_UART0->EVENTS_TXDRDY = 0;
	}
}

/**
* @brief 处理接收完成中断
* @retval 接收到的字节
*/

uint8_t drv_uart_deal_irq_rx_end(void)
{	
	NRF_UART0->EVENTS_RXDRDY = 0;
	return NRF_UART0->RXD;
}



console.h

/**
* Copyright (c), 2015-2025
* @file deal_console.h
* @brief 控制台接收数据处理模块头文件
* @author jdh
* @date 2016/7/28
* @update 2016/8/8
* @update 2017/10/20
*/

#ifndef _DEAL_CONSOLE_H_
#define _DEAL_CONSOLE_H_

/*********************************************************************
*							头文件
**********************************************************************/

#include "world.h"
#include "console.h"

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 接收处理
* @param rx:接收数据
*/

void deal_console_rx(T_Buffer rx);

#endif




console.c

/**
* Copyright (c), 2015-2025
* @file console.c
* @brief 控制台主文件
* @author jdh
* @date 2015/3/16
* @update 2015/6/30
* @update 2015/8/12
* @update 2016/10/25
* @update 2017/10/20
*/

/*********************************************************************
*							头文件
**********************************************************************/

#include "console.h"

/*********************************************************************
*							宏定义
**********************************************************************/

/**
* @brief 观察者最大个数
*/

#define MAX_OBSERVER				10

/*********************************************************************
*							静态变量
**********************************************************************/

/**
* @brief pt任务变量
*/

static struct pt Pt_Task;

/**
* @brief 接收数据观察者列表
*/

static T_Console_Rx Observer[MAX_OBSERVER];
static uint8_t Len_Observer = 0;

/**
* @brief 接收数据
*/

static T_Buffer Buffer_Rx;
static bool Is_Rx = false;

/*********************************************************************
*							静态函数
**********************************************************************/

static int pt_run(struct pt *pt);
static void notify_observer(void);

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 模块载入
*/

void console_load(void)
{
	PT_INIT(&Pt_Task);
}

/**
* @brief 模块运行
*/

void console_run(void)
{
	pt_run(&Pt_Task);
}

static int pt_run(struct pt *pt)
{
	static T_Time time_delay;

	PT_BEGIN(pt);
	
	time_delay = get_time();
	PT_WAIT_UNTIL(pt,sub_time_safe(get_time(),&time_delay) > INTERVAL_CONSOLE * 1000);
	
	if (Is_Rx)
	{
		Is_Rx = false;
	}
	else
	{
		if (Buffer_Rx.len > 0)
		{
			notify_observer();
			Buffer_Rx.len = 0;
		}
	}
	
	PT_END(pt);
}

static void notify_observer(void)
{
	for (int i = 0;i < Len_Observer;i++)
	{
		Observer[i](Buffer_Rx);
	}
}

/**
* @brief 注册观察者
* @param function:观察者函数指针
*/

void console_register_observer(T_Console_Rx function)
{
	Observer[Len_Observer++] = function;
}

/**
* @brief 串口中断处理函数
* @param data:接收数据存放地址
*/

void console_irq_handler(void)                              
{   
	Buffer_Rx.buf[Buffer_Rx.len++] = drv_uart_deal_irq_rx_end();
	Is_Rx = true;
} 

/**
* @brief 向控制台发送数据
* @param data:发送数据存放地址
* @param size:发送数据字节数
*/

void console_tx(uint8_t *data,uint16_t size)
{
	drv_uart_tx(data, size);
}



中断处理函数:

void UARTE0_UART0_IRQHandler(void)
{
	console_irq_handler();
}


测试用例:

deal_console.h:

/**
* Copyright (c), 2015-2025
* @file deal_console.h
* @brief 控制台接收数据处理模块头文件
* @author jdh
* @date 2016/7/28
* @update 2016/8/8
* @update 2017/10/20
*/

#ifndef _DEAL_CONSOLE_H_
#define _DEAL_CONSOLE_H_

/*********************************************************************
*							头文件
**********************************************************************/

#include "world.h"
#include "console.h"

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 接收处理
* @param rx:接收数据
*/

void deal_console_rx(T_Buffer rx);

#endif




deal_console.c:

/**
* Copyright (c), 2015-2025
* @file deal_console.c
* @brief 控制台接收数据处理模块主文件
* @date 2016/7/28
* @upate 2016/7/29
* @upate 2016/8/1
* @upate 2016/8/8
* @upate 2016/8/10
* @upate 2016/8/11
* @upate 2016/8/17
* @upate 2016/8/18
* @update 2016/9/2
* @update 2016/9/5
* @update 2016/9/12
* @update 2016/9/13
* @update 2016/9/21
* @update 2016/9/23
* @update 2016/10/19
* @update 2017/10/20
* @update 2017/10/23
*/

/*********************************************************************
*							头文件
**********************************************************************/

#include "deal_console.h"
#include "radio_rx.h"

/*********************************************************************
*							静态函数
**********************************************************************/

/**
* @brief 搜索字符串出现下标
* @param src:源字符串
* @param dst:目标字符串
* @param begin:开始下标
* @param num:第几次出现,从1开始
* @retval -1:失败,其他:下标
*/

static int search_string(char *src,char *dst,int begin,int num);

/**
* @brief 复位基站
* @param offset:正文偏移
* @param rx:接收数据
*/

static void deal_cmd_bus_reset(uint16_t offset, T_Buffer rx);

/**
* @brief 设置接收频点
* @param offset:正文偏移
* @param rx:接收数据
*/

static void deal_cmd_bus_set_rx_freq(uint16_t offset, T_Buffer rx);

/**
* @brief 读取接收频点
* @param offset:正文偏移
* @param rx:接收数据
*/

static void deal_cmd_bus_get_rx_freq(uint16_t offset, T_Buffer rx);

static void help(void);

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 接收处理
* @param rx:接收数据
*/

void deal_console_rx(T_Buffer rx)
{
	uint16_t offset = 0;
	uint8_t cmd = 0;
	int result = 0;
	
	//读取命令字
	//复位
	result = search_string((char *)rx.buf, "RESET", 0, 1);
	if (result != -1)
	{
		//处理
		deal_cmd_bus_reset(result, rx);
		return;
	}
	
	//设置接收频点
	result = search_string((char *)rx.buf, "SET_FREQ", 0, 1);
	if (result != -1)
	{
		//处理
		deal_cmd_bus_set_rx_freq(result, rx);
		return;
	}
	
	//读取接收频点
	result = search_string((char *)rx.buf, "READ_FREQ", 0, 1);
	if (result != -1)
	{
		//处理
		deal_cmd_bus_get_rx_freq(result, rx);
		return;
	}
	
	if (rx.len == 1 && rx.buf[0] == 'H')
	{
		help();
	}
}

/**
* @brief 搜索字符串出现下标
* @param src:源字符串
* @param dst:目标字符串
* @param begin:开始下标
* @param num:第几次出现,从1开始
* @retval -1:失败,其他:下标
*/

static int search_string(char *src,char *dst,int begin,int num)
{
	int i = 0;
	int j = 0;
	int len1 = 0;
	int len2 = 0;
	int count = 0;
	
	if (num == 0)
	{
		return -1;
	}
	
	len1 = strlen(src);
	len2 = strlen(dst);
	
	if (len1 < len2)
	{
		return -1;
	}
	
	for (i = begin;i <= len1 - len2;i++)
	{
		for (j = 0;j < len2;j++)
		{
			if (src[i + j] != dst[j])
			{
				break;
			}
		}
		if (j >= len2)
		{
			count++;
			if (count == num)
			{
				return i;
			}
		}
	}
	
	return -1;
}

/**
* @brief 复位基站
* @param offset:正文偏移
* @param rx:接收数据
*/

static void deal_cmd_bus_reset(uint16_t offset, T_Buffer rx)
{	
	//回复
	console_tx((uint8_t *)"CONFIRM+RESET\r\n", strlen("CONFIRM+RESET\r\n"));
	//复位
	NVIC_SystemReset();
}

/**
* @brief 设置接收频点
* @param offset:正文偏移
* @param rx:接收数据
*/

static void deal_cmd_bus_set_rx_freq(uint16_t offset, T_Buffer rx)
{
	int freq, len;
	
	sscanf((char *)rx.buf, "SET_FREQ+%d+%d", &freq, &len);
	// 判断频率是否正确
	if (freq < 2360 || freq > 2500)
	{
		return;
	}
	// 判断长度是否正确
	if (len > 100)
	{
		return;
	}
	
	//设置接收频点
	//radio_rx_start(freq, len);
	radio_rx_stop();
	radio_rx_start(freq, len);
	
//	drv_radio_set_frequency(freq);
//	drv_radio_set_playload_length(len);
	
	//回复
	console_tx((uint8_t *)"CONFIRM+SET_FREQ\r\n", strlen("CONFIRM+SET_FREQ\r\n"));
}

/**
* @brief 读取接收频点
* @param offset:正文偏移
* @param rx:接收数据
*/

static void deal_cmd_bus_get_rx_freq(uint16_t offset, T_Buffer rx)
{
	int freq, len;
	char arr[128] = {0};
	
	//模块接收频点
	freq = drv_radio_get_frequency();
	len = drv_radio_get_playload_length();
	
	//回复
	sprintf(arr, "SEND_FREQ+%d+%d\r\n", freq, len);
	console_tx((uint8_t *)arr, strlen(arr));
	
}

static void help(void)
{
	char log_out[100] = {0};
	
	strcpy(log_out,"*******************************************\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"             Sniffer帮助界面            \r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"硬件版本:%d 软件版本:%d\r\n", VERSION_HARD, VERSION_SOFT);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"H:帮助\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"RESET:复位\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"SET_FREQ:设置频点.例:SET_FREQ+2400\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"READ_FREQ:读取频点\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"*******************************************\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
}



在main.c中注册及调用:

int main(void)
{
	world_load();

	
	spi_load();
	reg_management_load();
	test_load();
	console_load();
	
	drv_radio_config(RADIO_TXPOWER_POS4DBM, 2400, RADIO_BAUDRATE_1M, 0x11223344, 14);
	
//	// test
//	radio_tx_stop();
//	radio_rx_stop();
//	
//	RADIO_SR.FREQ = 40;
//	RADIO_SR.LENGTH = 14;
//	RADIO_SR.STATE = BITS_RADIO_STATE_RX;
//	radio_rx_start(RADIO_SR.FREQ + BITS_BASE_FREQ, RADIO_SR.LENGTH);
	
	
	// 观察者注册
	spi_register_observer(reg_management_deal_spi_rx);
	radio_tx_register_observer(reg_management_deal_radio_tx_events);
	radio_rx_register_observer(reg_management_deal_radio_rx_events);
	console_register_observer(deal_console_rx);
	
	radio_rx_start(2400, 14);
	
	uint8_t arr[28] = {0};
	while (1)
	{
		radio_rx_run();
		console_run();
	}
}


Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐