合宙Air系列模块外部总线接口常见用法-SPI总线,下

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脚本尚未编写,有兴趣的朋友可以试试自行编写测试,谢谢。

上次更新 2021-01-28