提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
蓝牙芯片nRF51822开发系列(二):UART及内置温度传感器详解与使用
- 前言(文章末尾获取工程源码)
- 一、UART详解
- 1.UART结构
- 2.寄存器
- 二、使用步骤(在上一篇文章的工程基础下)
- 1.初始化
- 2.发送和接收数据
- 3.测试
- 4.使用printf打印
- 三、内置温度传感器
- 四、获取工程源码
前言(文章末尾获取工程源码)
通用异步收发传输器(UART),是SoC重要的通信方式。不仅能用来开发调试,甚至还可以做成透传功能。本次结合nRF51822内置的温度传感器进行实验。
一、UART详解
1.UART结构
上图为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方向和相关寄存器,如下图。
无中断方式:
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);
}
}
中断方式:以接收为中断,接收到一个数据就发送这个数据。
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);
}
4.使用printf打印
重定向fputc函数,串口发送更方便。
int fputc(int ch, FILE *f)
{
uart_send_byte((unsigned char) ch);
return (ch);
}
三、内置温度传感器
启动START任务开始测量,STOP任务停止测量。测量完成后,产生DATARDY事件,表明数据已经在TEMP寄存器准备好。使用HFCLK为时钟源时测量更加精确。测量完成后,传感器模拟电路自动关闭节省功耗。所以开始一次START任务,只会测量一次,测量完成后自动关闭。下次测量需要重新开启START任务。
精度为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);
}