void simple_uart_config( uint8_t rts_pin_number,
uint8_t txd_pin_number,
uint8_t cts_pin_number,
uint8_t rxd_pin_number,
bool hwfc)
{
/** @snippet [Configure UART RX and TX pin] */
nrf_gpio_cfg_output(txd_pin_number);
nrf_gpio_cfg_input(rxd_pin_number, NRF_GPIO_PIN_NOPULL);
NRF_UART0->PSELTXD = txd_pin_number;
NRF_UART0->PSELRXD = rxd_pin_number;
/** @snippet [Configure UART RX and TX pin] */
if (hwfc)
{
nrf_gpio_cfg_output(rts_pin_number);
nrf_gpio_cfg_input(cts_pin_number, NRF_GPIO_PIN_NOPULL);
NRF_UART0->PSELCTS = cts_pin_number;
NRF_UART0->PSELRTS = rts_pin_number;
NRF_UART0->CONFIG = (UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos);
}
NRF_UART0->BAUDRATE = (UART_BAUDRATE_BAUDRATE_Baud38400 << UART_BAUDRATE_BAUDRATE_Pos);
NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
NRF_UART0->TASKS_STARTTX = 1;
NRF_UART0->TASKS_STARTRX = 1;
NRF_UART0->EVENTS_RXDRDY = 0;
}
下面对这段程序进行说明,程序的参数为RTS(Request To Send,请求发送)引脚号、TXD(数据发送信号线)引脚号、CTS(Clear To Send,发送允许)引脚号和RXD(数据接收信号线)引脚号。
UART引脚 | 名称 | 作用 | 方向 | 开发板中对应的引脚号 |
RTS | Request To Send | nRF51822向外部发出的请求发送信号,外部设备接到此请求信号后,开始发送数据,nRF51822通过RXD信号线接收数据(低电平有效) | 输出 | |
TXD | 输出 | P0.09 | ||
CTS | Clear To Send | 外部向nRF51822发送的发送允许信号,nRF51822接收到此信号后,开始发送数据,nRF51822通过TXD信号线开始发送数据(低电平有效) | 输入 | |
RXD | 输入 | P0.11 |
RTS (Require ToSend,发送请求)为输出信号,用于指示本设备准备好可接收数据,低电平有效,低电平说明本设备可以接收数据。
CTS (Clear ToSend,发送允许)为输入信号,用于判断是否可以向对方发送数据,低电平有效,低电平说明本设备可以向对方发送数据。
此处有人将CTS翻译为发送允许,我感觉的确比翻译为清除发送好。因为CTS是对方的RTS控制己方的CTS是否允许发送的功能。/* Register: UART_BAUDRATE */
/* Description: UART Baudrate. */
/* Bits 31..0 : UART baudrate. */
#define UART_BAUDRATE_BAUDRATE_Pos (0UL) /*!< Position of BAUDRATE field. */
#define UART_BAUDRATE_BAUDRATE_Msk (0xFFFFFFFFUL << UART_BAUDRATE_BAUDRATE_Pos) /*!< Bit mask of BAUDRATE field. */
#define UART_BAUDRATE_BAUDRATE_Baud1200 (0x0004F000UL) /*!< 1200 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud2400 (0x0009D000UL) /*!< 2400 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud4800 (0x0013B000UL) /*!< 4800 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud9600 (0x00275000UL) /*!< 9600 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud14400 (0x003B0000UL) /*!< 14400 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud19200 (0x004EA000UL) /*!< 19200 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud28800 (0x0075F000UL) /*!< 28800 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud38400 (0x009D5000UL) /*!< 38400 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud57600 (0x00EBF000UL) /*!< 57600 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud76800 (0x013A9000UL) /*!< 76800 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud115200 (0x01D7E000UL) /*!< 115200 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud230400 (0x03AFB000UL) /*!< 230400 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud250000 (0x04000000UL) /*!< 250000 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud460800 (0x075F7000UL) /*!< 460800 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud921600 (0x0EBEDFA4UL) /*!< 921600 baud. */
#define UART_BAUDRATE_BAUDRATE_Baud1M (0x10000000UL) /*!< 1M baud. */
在好多情况下,nRF51822都是通过这样的方式来实现寄存器的写入,而且一般情况下寄存器都按照这样的规则,显示NRF_XX(XX表示某一设备),然后用箭头操作符指向相应的寄存器,当为任务寄存器时,为TASKS_XX(XX表示某一任务寄存器);当为事件寄存器时,为EVENTS_XX(XX表示某一事件寄存器)。其实在关于nRF51822外设的declaration中就可以看到nRF51822有哪些外设资源,例如有多少个TIMER,多少个UART。现将nRF51 SDK中的头文件nrf51.h中关于外设基地址的宏定义复制如下,可以看到有TIMER0、TIMER1、TIEMR2三个基地址,则就知到nRF51822有三个定时/计数器。
/* ================================================================================ */
/* ================ Peripheral declaration ================ */
/* ================================================================================ */
#define NRF_POWER ((NRF_POWER_Type *) NRF_POWER_BASE)
#define NRF_CLOCK ((NRF_CLOCK_Type *) NRF_CLOCK_BASE)
#define NRF_MPU ((NRF_MPU_Type *) NRF_MPU_BASE)
#define NRF_PU ((NRF_PU_Type *) NRF_PU_BASE)
#define NRF_AMLI ((NRF_AMLI_Type *) NRF_AMLI_BASE)
#define NRF_RADIO ((NRF_RADIO_Type *) NRF_RADIO_BASE)
#define NRF_UART0 ((NRF_UART_Type *) NRF_UART0_BASE)
#define NRF_SPI0 ((NRF_SPI_Type *) NRF_SPI0_BASE)
#define NRF_TWI0 ((NRF_TWI_Type *) NRF_TWI0_BASE)
#define NRF_SPI1 ((NRF_SPI_Type *) NRF_SPI1_BASE)
#define NRF_TWI1 ((NRF_TWI_Type *) NRF_TWI1_BASE)
#define NRF_SPIS1 ((NRF_SPIS_Type *) NRF_SPIS1_BASE)
#define NRF_GPIOTE ((NRF_GPIOTE_Type *) NRF_GPIOTE_BASE)
#define NRF_ADC ((NRF_ADC_Type *) NRF_ADC_BASE)
#define NRF_TIMER0 ((NRF_TIMER_Type *) NRF_TIMER0_BASE)
#define NRF_TIMER1 ((NRF_TIMER_Type *) NRF_TIMER1_BASE)
#define NRF_TIMER2 ((NRF_TIMER_Type *) NRF_TIMER2_BASE)
#define NRF_RTC0 ((NRF_RTC_Type *) NRF_RTC0_BASE)
#define NRF_TEMP ((NRF_TEMP_Type *) NRF_TEMP_BASE)
#define NRF_RNG ((NRF_RNG_Type *) NRF_RNG_BASE)
#define NRF_ECB ((NRF_ECB_Type *) NRF_ECB_BASE)
#define NRF_AAR ((NRF_AAR_Type *) NRF_AAR_BASE)
#define NRF_CCM ((NRF_CCM_Type *) NRF_CCM_BASE)
#define NRF_WDT ((NRF_WDT_Type *) NRF_WDT_BASE)
#define NRF_RTC1 ((NRF_RTC_Type *) NRF_RTC1_BASE)
#define NRF_QDEC ((NRF_QDEC_Type *) NRF_QDEC_BASE)
#define NRF_LPCOMP ((NRF_LPCOMP_Type *) NRF_LPCOMP_BASE)
#define NRF_COMP ((NRF_COMP_Type *) NRF_COMP_BASE)
#define NRF_SWI ((NRF_SWI_Type *) NRF_SWI_BASE)
#define NRF_NVMC ((NRF_NVMC_Type *) NRF_NVMC_BASE)
#define NRF_PPI ((NRF_PPI_Type *) NRF_PPI_BASE)
#define NRF_FICR ((NRF_FICR_Type *) NRF_FICR_BASE)
#define NRF_UICR ((NRF_UICR_Type *) NRF_UICR_BASE)
#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
uint8_t simple_uart_get(void)
{
while (NRF_UART0->EVENTS_RXDRDY != 1)
{
// Wait for RXD data to be received
}
NRF_UART0->EVENTS_RXDRDY = 0;
return (uint8_t)NRF_UART0->RXD;
}
void simple_uart_put(uint8_t cr)
{
NRF_UART0->TXD = (uint8_t)cr;
while (NRF_UART0->EVENTS_TXDRDY!=1)
{
// Wait for TXD data to be sent
}
NRF_UART0->EVENTS_TXDRDY=0;
}
void simple_uart_putstring(const uint8_t *str)
{
uint_fast8_t i = 0;
uint8_t ch = str[i++];
while (ch != '\0')
{
simple_uart_put(ch);
ch = str[i++];
}
}
bool simple_uart_get_with_timeout(int32_t timeout_ms, uint8_t *rx_data)
{
bool ret = true;
while (NRF_UART0->EVENTS_RXDRDY != 1)
{
if (timeout_ms-- >= 0)
{
// wait in 1ms chunk before checking for status
nrf_delay_us(1000);
}
else
{
ret = false;
break;
}
} // Wait for RXD data to be received
if (timeout_ms >= 0)
{
// clear the event and set rx_data with received byte
NRF_UART0->EVENTS_RXDRDY = 0;
*rx_data = (uint8_t)NRF_UART0->RXD;
}
return ret;
}
以下为该函数的说明
/** @brief Function for reading a character from UART with timeout on how long to wait for the byte to be received.
Execution is blocked until UART peripheral detects character has been received or until the timeout expires, which even occurs first
\return bool True, if byte is received before timeout, else returns False.
@param timeout_ms maximum time to wait for the data.
@param rx_data pointer to the memory where the received data is stored.
*/
bool simple_uart_get_with_timeout(int32_t timeout_ms, uint8_t *rx_data);
NRF_UART0->INTENSET=UART_INTENSET_RXDRDY_Enabled<
在这里要注意一点,对相关外设的INTENSET寄存器配置并没有完成对中断的使能,还需要对中断向量控制器NVIC(Nested Vectored Interrupt Controller)中的中断使能寄存器ISER进行配置,庆幸的是,一般的嵌入式产品官方SDK中都有相应的库函数直接完成配置。
NVIC_EnableIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn,1);