Air720SL模块 SPI接口简介
nRF24L01简介
nRF24L01 是一款工作在2.4~2.5GHz 世界通用ISM 频段的单片无线收发器芯片无线收发器,下面是芯片信息,以及参考电路
工作电压 1.9~3.6V
最大发射功率 0 dBm
发射模式下电流消耗0dBm 11.3 mA
接收模式下电流消耗2000kbps 12.3 mA
掉电模式下电流消耗 900 nA
查阅nRF24L01的工作电压可知,可以使芯片工作在2.0V,即可匹配Air720SL的1.8V的IO电平。小功率的可调LDO很多,如AMS1117-ADJ,这里就不多介绍了。
连接示意图如下:
下面是发射端的代码:
主程序
-- Example 1: nrf24 transmitter
-- Features: fixed payload length
r = require("nrf24")
r.nrf24_hw_init()
r.nrf24_init_node()
r.nrf24_stop_listening()
r.nrf24_set_channel(50)
r.nrf24_set_xmit_address({0x0a, 0x0b, 0x0c, 0x0d, 0x0e})
r.nrf24_set_recv_address({0x0a, 0x0b, 0x0c, 0x0d, 0x0e})
r.nrf24_set_payload_size(15)
i=0
--发送Demo
r.nrf24_power_up()
sys.timerLoopStart(function()
r.nrf24_reset()
local s_send="ABC"..i
log.info("nrf24l01","xmit packet...", table.concat(string.utf8ToTable(s_send)))
r.nrf24_send_packet(string.utf8ToTable(s_send))
i=i+1
end,1000)
function gpio61IntFnc(msg)
end
--GPIO61配置为中断,可通过getGpio61Fnc()获取输入电平,产生中断时,自动执行gpio61IntFnc函数
getGpio61Fnc = pins.setup(61,gpio61IntFnc)
nRF24L01 底层驱动
-- nRF24 module 此代码参考了github开源项目 https://github.com/geomatsi/nodemcu-tests
local modname = ...
local M = {}
_G[modname] = M
require "pins"
--
-- module constants
--
-- nRF24 commands
local R_REGISTER = 0x00
local W_REGISTER = 0x20
local REGISTER_MASK = 0x1F
local R_RX_PL_WID = 0x60
local R_RX_PAYLOAD = 0x61
local W_TX_PAYLOAD = 0xA0
local FLUSH_TX = 0xE1
local FLUSH_RX = 0xE2
local NOP = 0xFF
-- nRF24 register map
local CONFIG = 0x00
local SETUP_RETR = 0x04
local RF_CH = 0x05
local RF_SETUP = 0x06
local STATUS = 0x07
local RX_ADDR_P0 = 0x0A
local TX_ADDR = 0x10
local RX_PW_P0 = 0x11
local DYNPD = 0x1C
local FEATURE = 0x1D
local EN_RXADDR = 0x02
local FIFO_STATUS = 0x17
-- register bits
local ARD = 4
local ARC = 0
local RF_PWR_LOW = 1
local RF_PWR_HIGH = 2
local RF_DR_LOW = 5
local RF_DR_HIGH = 3
local EN_CRC = 3
local CRCO = 2
local RX_DR = 6
local TX_DS = 5
local MAX_RT = 4
local PRIM_RX = 0
local PWR_UP = 1
local EN_DPL = 2
local ERX_P0 = 0
local RX_EMPTY = 0
--
-- module locals
--
local PAYLOAD = 0
local CE_PIN = 63
local CS_PIN = 34
local function stringtoTable(str)
local table = {}
for i=1,#str do
table[i] = string.sub(str,i,i)
end
return table
end
-- set NRF24 CE gpio level
local function nrf24_ce(value)
local level = (value > 0) and 1 or 0
pins.setup(CE_PIN,level)
end
-- set NRF24 CSN gpio level
local function nrf24_csn(value)
local level = (value > 0) and 1 or 0
pins.setup(CS_PIN,level)
end
-- reverse 5byte pipe address
local function reverse_addr(addr_in)
local addr_out = {}
for i = 1, 5 do
addr_out[i] = addr_in[5 - i + 1] or 0x0
end
return addr_out
end
--
-- module exports
--
-- init nrf24 module
function M.nrf24_hw_init()
--打开SPI引脚的供电
pmd.ldoset(6,pmd.LDO_VMMC)
spi.setup(0,0,0,8,110000,1)
pins.setup(CE_PIN,1)
pins.setup(CS_PIN,1)
end
function M.nrf24_reset()
status = bit.bor(bit.lshift(1, RX_DR), bit.lshift(1, TX_DS), bit.lshift(1, MAX_RT))
M.nrf24_write_register(STATUS, status)
end
--发送一条指令
function M.nrf24_send_cmd(cmd)
nrf24_csn(0)
local ret=0
ret=spi.send(0,string.char(cmd))
nrf24_csn(1)
return ret
end
--发送一条请求,并返回单字节数据
function M.nrf24_send_req(req)
nrf24_csn(0)
local rsp=spi.send_recv(0, string.char(req)..string.char(0xff))
nrf24_csn(1)
return string.byte(rsp:sub(2,2))
end
--发送一条请求,并返回指定字节长度的数据
function M.nrf24_msend_req(req, len)
input = {}
for i = 1, len do
input[i] = string.char(0xff)
end
nrf24_csn(0)
local output=spi.send_recv(0, string.char(req)..table.concat(input))
nrf24_csn(1)
return stringtoTable(output:sub(2,-1))
end
--发送一条命令,并返回状态
function M.nrf24_msend_cmd(cmd, values)
nrf24_csn(0)
local ret=spi.send_recv(0,string.char(cmd)..table.concat(values))
nrf24_csn(1)
return string.byte(ret:sub(1,1))
end
--获取状态
function M.nrf24_get_status()
nrf24_csn(0)
local status=spi.send_recv(0, string.char(NOP))
nrf24_csn(1)
return string.byte(status)
end
--读取单个寄存器的值
function M.nrf24_read_register(reg)
nrf24_csn(0)
local register=string.char(bit.bor(R_REGISTER, bit.band(REGISTER_MASK, reg)))
local ret=spi.send_recv(0,register..string.char(0xff))
nrf24_csn(1)
return string.byte(ret:sub(2,2))
end
--读取多个寄存器的值
function M.nrf24_mread_register(reg, len)
input = {}
for i = 1, len do
input[i] = string.char(0xff)
end
nrf24_csn(0)
local register=string.char(bit.bor(R_REGISTER, bit.band(REGISTER_MASK, reg)))
local output=spi.send_recv(0,register..table.concat(input))
nrf24_csn(1)
return stringtoTable(output:sub(2,-1))
end
--写入单个寄存器的值
function M.nrf24_write_register(reg, value)
nrf24_csn(0)
local register=string.char(bit.bor(W_REGISTER, bit.band(REGISTER_MASK, reg)))
local ret=spi.send_recv(0,register..string.char(value))
nrf24_csn(1)
return string.byte(ret)
end
--写入多个寄存器的值
function M.nrf24_mwrite_register(reg, values)
nrf24_csn(0)
local register=string.char(bit.bor(W_REGISTER, bit.band(REGISTER_MASK, reg)))
local ret=spi.send_recv(0,register..table.concat(values))
nrf24_csn(1)
return string.byte(ret:sub(1,1))
end
function M.nrf24_stop_listening()
config = M.nrf24_read_register(CONFIG)
config = bit.band(config, bit.bnot(bit.lshift(1, PRIM_RX)))
M.nrf24_write_register(CONFIG, config)
M.nrf24_mwrite_register(RX_ADDR_P0, {0x0, 0x0, 0x0, 0x0, 0x0})
M.nrf24_mwrite_register(TX_ADDR, {0x0, 0x0, 0x0, 0x0, 0x0})
end
function M.nrf24_start_listening()
config = M.nrf24_read_register(CONFIG)
config = bit.bor(config, bit.lshift(1, PRIM_RX), bit.lshift(1, PWR_UP))
M.nrf24_write_register(CONFIG, config)
status = bit.bor(bit.lshift(1, RX_DR), bit.lshift(1, TX_DS), bit.lshift(1, MAX_RT))
M.nrf24_write_register(STATUS, status)
nrf24_ce(1);
rtos.sleep(130)
end
function M.nrf24_set_xmit_address(address)
---- address is 5bytes length
---- address is written inversely
addr = reverse_addr(address)
M.nrf24_mwrite_register(RX_ADDR_P0, addr)
M.nrf24_mwrite_register(TX_ADDR, addr)
end
-- TODO: support all 6 rx pipes
function M.nrf24_set_recv_address(address)
---- address is 5bytes length
---- address is written inversely
addr = reverse_addr(address)
M.nrf24_mwrite_register(RX_ADDR_P0, addr)
pipes = M.nrf24_read_register(EN_RXADDR)
pipes = bit.bor(pipes, bit.lshift(1, ERX_P0))
M.nrf24_write_register(EN_RXADDR, pipes)
end
-- TODO: support all 6 rx pipes
function M.nrf24_data_available()
status = M.nrf24_get_status()
result = M.nrf24_read_register(FIFO_STATUS)
--log.info("irf24","Show me FIFO STATUS ",result)
data_ready = 0
if (bit.isclear(result, RX_EMPTY)) then
-- TODO: get pipe which received data
-- pipe_num = ( status >> RX_P_NO ) & BIN(111);
M.nrf24_write_register(STATUS, bit.lshift(1, RX_DR))
if (bit.isset(status, TX_DS)) then
M.nrf24_write_register(STATUS, bit.lshift(1, TX_DS))
end
data_ready = 1
end
return data_ready
end
function M.nrf24_get_dynamic_payload_size()
size = M.nrf24_send_req(R_RX_PL_WID)
if (size > 32) then
-- radio noise received, dropping
M.nrf24_send_cmd(FLUSH_RX)
size = 0
end
return size
end
-- TODO: support all 6 rx pipes
function M.nrf24_data_read()
if (PAYLOAD == 0) then
len = M.nrf24_get_dynamic_payload_size()
else
len = PAYLOAD
end
output = M.nrf24_msend_req(R_RX_PAYLOAD, len)
return output
end
function M.nrf24_set_payload_size(payload_size)
PAYLOAD = payload_size
if (PAYLOAD > 32) then
PAYLOAD = 32
end
if (PAYLOAD < 1) then
PAYLOAD = 1
end
M.nrf24_write_register(RX_PW_P0, PAYLOAD)
end
function M.nrf24_set_dynamic_payload()
PAYLOAD = 0
-- FIXME: we may need to enable writing to FEATURE register
value = M.nrf24_read_register(FEATURE)
value = bit.bor(value, bit.lshift(1, EN_DPL))
M.nrf24_write_register(FEATURE, value)
-- enable dynamic payload for all the pipes
M.nrf24_write_register(DYNPD, 0x3f)
end
function M.nrf24_set_channel(channel)
M.nrf24_write_register(RF_CH, channel)
end
function M.nrf24_power_up()
config = M.nrf24_read_register(CONFIG);
config = bit.bor(config, bit.lshift(1, PWR_UP))
M.nrf24_write_register(CONFIG, config)
end
function M.nrf24_send_packet(data)
xmit_data = {}
xmit_len = 32
-- set packet length for non-dynamic payload
if PAYLOAD > 0 then
xmit_len = PAYLOAD
end
for i = 1, xmit_len do
if (data[i] ~= nil) then
xmit_data[i] = data[i]
else
if PAYLOAD == 0 then
break
end
xmit_data[i] = 0x0
end
end
-- write packet to FIFO
M.nrf24_msend_cmd(W_TX_PAYLOAD, xmit_data)
-- xmit packet
nrf24_ce(1);
rtos.sleep(15)
nrf24_ce(0);
end
-- simple client node setup
function M.nrf24_init_node()
nrf24_ce(0)
-- let the radio some time to warm-up
rtos.sleep(500)
-- set maximum PA level
setup = M.nrf24_read_register(RF_SETUP)
setup = bit.bor(setup, bit.lshift(1, RF_PWR_LOW), bit.lshift(1, RF_PWR_HIGH))
M.nrf24_write_register(RF_SETUP, setup)
-- set data rate to 1Mbps
setup = M.nrf24_read_register(RF_SETUP)
setup = bit.band(setup, bit.bnot(bit.bor(bit.lshift(1, RF_DR_LOW), bit.lshift(1, RF_DR_HIGH))))
M.nrf24_write_register(RF_SETUP, setup)
-- set 16bit CRC
config = M.nrf24_read_register(CONFIG)
config = bit.bor(config, bit.lshift(1, EN_CRC), bit.lshift(1, CRCO))
M.nrf24_write_register(CONFIG, config)
-- configure retries
M.nrf24_write_register(SETUP_RETR, bit.bor(bit.lshift(bit.band(10, 0xf), ARD), bit.lshift(bit.band(0, 0xf), ARC)))
-- disable dynamic payloads
M.nrf24_write_register(DYNPD, 0);
-- reset current status
M.nrf24_write_register(STATUS, bit.bor(bit.lshift(1, RX_DR), bit.lshift(1, TX_DS), bit.lshift(1, MAX_RT)))
-- flush buffers
M.nrf24_send_cmd(FLUSH_RX)
M.nrf24_send_cmd(FLUSH_TX)
end
return M
此代码的作用是以15字节固定字长发送英文字母ABC+1位随机整数。接收代码的底层函数上文已经包括,但上层lua脚本尚未编写,有兴趣的朋友可以试试自行编写测试,谢谢。