提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


蓝牙芯片nRF51822开发系列(二):UART及内置温度传感器详解与使用

  • 前言(文章末尾获取工程源码)
  • 一、UART详解
  • 1.UART结构
  • 2.寄存器
  • 二、使用步骤(在上一篇文章的工程基础下)
  • 1.初始化
  • 2.发送和接收数据
  • 3.测试
  • 4.使用printf打印
  • 三、内置温度传感器
  • 四、获取工程源码



前言(文章末尾获取工程源码)

通用异步收发传输器(UART),是SoC重要的通信方式。不仅能用来开发调试,甚至还可以做成透传功能。本次结合nRF51822内置的温度传感器进行实验。


一、UART详解

1.UART结构

Android 蓝牙 传感器 蓝牙传感器原理_单片机

上图为nRF51822的UART结构图。nRF51822没有固定的引脚,故使用时需要指定4个物理管脚,包括TXD,RXD,CTS,RTS。RXD接收端有6个字节的FIFO缓存,CTS和RTS用于流量控制,当RXD的FIFO即将溢出时,防止因为溢出造成数据丢失,RTS会输出相应的电平信号通知发送方。CTS作用同理,由于在实际应用中很少使用,故将CTS和RTS置0xFFFFFFFF,使其失能。

2.寄存器

寄存器详解:

  • STARTTX(STARTRX):开始发送(接收)任务;
  • STOPTX(STOPRX):停止发送(接收)任务;
  • PSELRTS(PSELRTS):置0xFFFFFFFF,失能;
  • PSELTXD(PSELRXD):取值[0…31],指定物理管脚;
  • TXDRDY、RXDRDY:TXD每写入一字节数据,就会产生TXDRDY事件;有数据进入到RXD,就会产生RXDRDY事件。

二、使用步骤(在上一篇文章的工程基础下)

1.初始化

初始化需要设置管脚的GPIO方向和相关寄存器,如下图。

Android 蓝牙 传感器 蓝牙传感器原理_stm32_02

Android 蓝牙 传感器 蓝牙传感器原理_单片机_03

无中断方式:

void uart_init(){
	
	nrf_gpio_cfg_input(UART_RX, NRF_GPIO_PIN_NOPULL);
	nrf_gpio_cfg_output(UART_TX);		//设置管脚方向
	
	NRF_UART0->PSELRXD = UART_RX;
	NRF_UART0->PSELTXD = UART_TX;
	NRF_UART0->PSELRTS = 0XFFFFFFFF;
	NRF_UART0->PSELCTS = 0XFFFFFFFF;	//指定物理管脚
	
	NRF_UART0->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud115200;	//设置波特率
	NRF_UART0->CONFIG = 0;		//无流量控制
	
	NRF_UART0->EVENTS_RXDRDY = 0;
	NRF_UART0->EVENTS_TXDRDY = 0;		//清除事件

	NRF_UART0->ENABLE = 4;		//使能UART
	
	NRF_UART0->TASKS_STARTRX  = 1;
	NRF_UART0->TASKS_STARTTX = 1;		//开始任务
	
}

中断方式:

void uart_irq_init(){
	
	nrf_gpio_cfg_input(UART_RX, NRF_GPIO_PIN_NOPULL);
	nrf_gpio_cfg_output(UART_TX);
	
	NRF_UART0->PSELRXD = UART_RX;
	NRF_UART0->PSELTXD = UART_TX;
	NRF_UART0->PSELRTS = 0XFFFFFFFF;
	NRF_UART0->PSELCTS = 0XFFFFFFFF;
	
	NRF_UART0->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud115200;
	NRF_UART0->CONFIG = 0;
	
	NRF_UART0->EVENTS_RXDRDY = 0;
	NRF_UART0->EVENTS_TXDRDY = 0;

	NRF_UART0->INTENSET = 1 << 2;	//开启接收中断
	
	NRF_UART0->ENABLE = 4;	
	NRF_UART0->TASKS_STARTRX  = 1;
	NRF_UART0->TASKS_STARTTX = 1;
	
	NVIC_SetPriority(UART0_IRQn, 1);
    NVIC_ClearPendingIRQ(UART0_IRQn);
    NVIC_EnableIRQ(UART0_IRQn);		//系统开启中断
}

2.发送和接收数据

需要注意的是,无论发送和接收,都要把TXDRDY或RXDRDY事件清除。

void uart_send_byte(uint8_t data ){
	
	NRF_UART0->EVENTS_TXDRDY = 0;
	NRF_UART0->TXD = data;
	while(NRF_UART0->EVENTS_TXDRDY == 0);
}

uint8_t uart_recive_byte(uint8_t *data)
{
	
	if(NRF_UART0->EVENTS_RXDRDY != 0){
	NRF_UART0->EVENTS_RXDRDY = 0;	

	*data = (uint8_t)NRF_UART0->RXD;
	return 1;
	}
	return 0;
}

3.测试

无中断方式:

int main(){
	
	uart_init();
	
	char data[] = "程序猿Aki";

	while(1){
		
		
		for(int i = 0; data[i]!='\0';i++)
		uart_send_byte(data[i]);
		
		nrf_delay_ms(1000);


		
	}
}

Android 蓝牙 传感器 蓝牙传感器原理_Android 蓝牙 传感器_04


中断方式:以接收为中断,接收到一个数据就发送这个数据。

int main(){

	uart_irq_init();
	
	while(1){	
		nrf_delay_ms(1000);		
	}
}

//中断处理函数
void UART0_IRQHandler(){
	uint8_t	str;
	if(uart_recive_byte(&str))
		uart_send_byte(str);
}

Android 蓝牙 传感器 蓝牙传感器原理_Android 蓝牙 传感器_05

4.使用printf打印

重定向fputc函数,串口发送更方便。

int fputc(int ch, FILE *f)
{
     uart_send_byte((unsigned char) ch);
      return (ch);
}

三、内置温度传感器

Android 蓝牙 传感器 蓝牙传感器原理_物联网_06


启动START任务开始测量,STOP任务停止测量。测量完成后,产生DATARDY事件,表明数据已经在TEMP寄存器准备好。使用HFCLK为时钟源时测量更加精确。测量完成后,传感器模拟电路自动关闭节省功耗。所以开始一次START任务,只会测量一次,测量完成后自动关闭。下次测量需要重新开启START任务。

Android 蓝牙 传感器 蓝牙传感器原理_物联网_07


精度为0.25摄氏度,最后结果需要乘以 0.25。

void temp_read(){
	int32_t temp; 
	
	NRF_TEMP->TASKS_START = 1;
	
	while(NRF_TEMP->EVENTS_DATARDY == 0);
	
	temp = NRF_TEMP->TEMP;
	
	printf("temp = %d °C",temp/4);
}

Android 蓝牙 传感器 蓝牙传感器原理_物联网_08