一次小模块的使用过程

作者: 良知犹存

前言:

最近帮人做了个小设备,使用了无线模块、触摸芯片,主要功能就是把触摸按键的信号无线传到控制继电器输出,MCU是STM8系列的芯片,其中使用过程中调试无线模块LC21S觉得挺好用的,就写了这篇文章。

作者:良知犹存

转载授权以及围观:欢迎添加微信公众号:羽林君


模块介绍: {模块介绍:}

LC12S 采用最新 2.4G SOC 技术,特点是免开发,视距 120 米,收发一体无需切换,串口透明传
输,提供通信协议,可迅速调试成功。用户只要了解串口通信,无需复杂的无线通讯知识,就能完成无
线通信产品的开发。没有数据包大小限制,延时短,半双工通讯,抗干扰能力强。

● 2.4GHz ISM 频段,使用无须申请

● 最大输出功率 12dBm

● 接收灵敏度-95dBm

● 发射工作电流 40mA@12dBm

● 接收工作电流 24mA

● 睡眠电流 3.5uA

● 标准 TTL 电平 UART 串口

● 工作频率可设置,多个模块频分复用,互不干扰

● 通讯协议转换及射频收发切换自动完成,用户无须干预,简单易用

● 通讯速率 0.6kbps -38.4kbps,用户可通过 AT 指令配置

引脚介绍: {引脚介绍:}

引脚引脚名称引脚功能描述
1VCC电源电源(接 2.2~3.6V)典型 3.3V
2RXT模块数据输出(TTL 电平)串口通信数据接收
3TXD模块数据输入(TTL 电平)串口通信数据发送
4SET设置位配置参数使能(低电平使能参数配置,高电平进入透传模式,其中悬空为高电平)
5CS休眠引脚接低电平时工作,高电平进入休眠模式,其中悬空为高电平
6GND电源接地

基本配置: {基本配置:}

设置模式:

一旦进入设置状态,SET 引脚配置必须是低电平,CS 引脚必须接低电平,且串口设置必须是数据位
8,波特率 9600,校验位 N,停止位 1,空中速率 1Mbps。因为初始化默认设置就是如此,如果后续你设置了自己的波特率,这个时候你需要把串口设置按照你修改后的配置来设置。

透传模式:

上电后,当 CS引脚接低电,进入工作模式,SET 脚是设置参数标志位,这个时候们可以进行悬空或者拉高处理,让模块进入透传数据模式。

设置模式数据的协议格式: {设置模式数据的协议格式:}

在官方的手册里面有关于协议内容的说明,其中有一些数据是保留位,默认发0x00就可以。

如图所示,们可以看到数据长度是18个byte,其中包括设备ID(Self ID)、组网ID(Net ID )、发射功率(RF Power)、通讯波特率设置(Baud 1Byte)、无线通讯通道设置(RF CHN)、设置时的通讯数据长度(Lenght 1Byte)、累加校验位(CheckSum);其中设置时的通讯数据长度是固定的18byte所以此处默认为0x12。

其他部分的设置参数,在手册中各有体现,其中组网ID需要按照自己定义的ID区间进行设置,因为这个唯一性会影响到你的模块组网情况。

其余的设置设置参数就不进行截图表示了,大家可以看一下相应的手册。

测试设置发送数据:

0xaa+0x5a+模块 ID+组网 ID(ID 必须相同)+0x00+RF 发射功率+0x00+串口速率
+0x00+RF 信道选择+0x00+0x00+0x12(字节长度)+0x00+和校验字节
注意:和校验字节=所有参数累加的字节

发送:
AA 5A 22 33 11 22 00 01 00 04 00 64 00 00 00 12 00 07

—>

参考后面的数据表格,以上配置参数设置无线模块为:
RF 发射功率:10dbm
串口速率:9600bps
RF 信道:100
模块 ID:0x2233
组网 ID:0x1122
和校验字节:07

接收: 设置完成后模块会返回相应数据
AA 5B 47 00 11 22 00 01 00 04 00 64 00 00 00 12 00 FA

<—

串口调试助手的信息:

实际设备连接情况:

设置模式接线示意图:

透传模式接线示意图:

代码实现: {代码实现:}

因为模式使用比较简单,初始化好设备串口外设,再把CS引脚和SET配置一下,就可以开始使用了,如果你只是简单测试,那你可能只需要使用默认设置,只是进行数据的透传,那你可以直接忽略这部分设置的代码部分,直接看nrf_send_normal_data()函数。

设置模式下的代码


定义一个设置协议的结构体:

typedef struct __attribute__((__packed__)){
    u16 head;                 //
    u16 self_id;                 //
    u16 net_id;                 //
    u8 nc1;               //
    u8 rf_power;          //
    u8 nc2;               //
    u8 rf_baud;          //
    u8 nc3;               //
    u8 rf_chn;          //
    u16 nc4;               //
    u8 nc5;               //
    u8 length;               //
    u8 nc6;               //
}SetSend; 

拉低SET引脚,进入设置模式:

u8 SetNrf(void)//
{
       GPIO_ResetBits(SET_PORT, SET_PIN);
       GPIO_ResetBits(CS_PORT, CS_PIN);

      u8 *p1 = malloc(18);
      memset(p1,0x00,18);

      SetSend *p = (SetSend*)p1;

      p->head= 0xaa5a;
      p->self_id = 0x2233;
      p->net_id = 0x1122;
      p->rf_power = 0x00;
      p->rf_baud = 0x04;
      p->rf_chn = 0x64;
      p->length = 0x12;      
      p1[sizeof(SetSend)] = CheckSum((u8*)p, sizeof(SetSend));
      USART_Transmit_String( sizeof(SetSend)+1,p1);

if DEBUG_DPRINT
      u8 *str = malloc(20);
      hex_str((u8*)p, sizeof(SetSend)+1, str);
      USART_Transmit_String(20,str);
//      printf("--->:%s\r\n", str);
      free(str);
endif

      free(p1);
      return 1;

}


数据透传的函数,这个时候SET引脚拉高,这个函数部分是自己写的一个简单的3byte的sta状态发送。
大家可以按照自己的实际使用情况进行修改。

void nrf_send_normal_data(u16 sta)
{
      GPIO_SetBits(SET_PORT, SET_PIN);
      u8 *p1 = malloc(3);
      memset(p1,0x00,3);
      memset(p1,0xAA,1);      
      memcpy(p1+1,&sta,2);
      USART_Transmit_String(3,p1);
      free(p1);

}

芯片初始化之后不能立即使用,需要等待几十ms才能正常工作,所以需要稍微等待一下。

串口接收解析部分,这部分代码就仁者见仁智者见智了,大家可以用很多种方法实现,只是贴了一下写的代码部分,仅供参考。
其中NRF_RestTime()函数是在定时器中计时,用来区分不同的数据帧。

u8  USART_RX_BUF[USART_MAX_RECV_LEN];
u16 USART_RX_STA=0;

u8 NRF_RecvdData(void)
{
    u8 ret = 0;
    if((USART_RX_STA&(1<<15)) != 0)
        ret = 1;
    return ret;
}
u16 NRF_RcvLen(void)
{
    return (USART_RX_STA & 0x7FFF);
}
u8* NRF_RcvBuff(void)
{
    return USART_RX_BUF;
}

void NRF_ClsRecvd(void)
{
    USART_RX_STA = 0;
}


typedef struct  __attribute__((__packed__))
{
  u32 stat    :1;
  u32 timOut  :1;
  u32 cunt    :15;
  u32 des     :15;
}TboxTimTypeDef;
TboxTimTypeDef gNRFTimeManage;
define TON   (1)
define TOFF  (0)

void TimerManageInit(TboxTimTypeDef *t,u8 stat,u16 destim)
{
  t->des  = destim;
  t->stat = stat;
  t->cunt = 0;
  t->timOut = 0;
}
void NRF_RestTime(void)
{
      if(gNRFTimeManage.stat == TON)
      {
              (gNRFTimeManage.cunt < gNRFTimeManage.des)?(gNRFTimeManage.cunt++):\
                      (TimerManageInit(&gNRFTimeManage,TOFF,0),USART_RX_STA |=1<<15);
      } 
}

void NRF_Irq(void)
{
    u8 res;       
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {    
        res =USART_ReceiveData8(USART1);
                if 0
        USART_SendData8(USART1,res);
        endif


                if((USART_RX_STA & ~(1<<15))<USART_MAX_RECV_LEN)
                {
                      TimerManageInit(&gNRFTimeManage,TON,5);
                      USART_RX_BUF[USART_RX_STA++]=res;      
                }else 
                {
                        USART_RX_STA|=1<<15;                
                } 
          }
    USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}

void Parse_NRF(void)
{

    if(NRF_RcvLen()>2)
    {
      u16 len = NRF_RcvLen(); 
      u8 *p = NRF_RcvBuff();
      u8 pos = 0;
      u16 *sta = (u16*)(p+1);
      while(pos < len){
        if(*p == 0xAA)
        {

          relay_ctrl(*sta);
          p += 3;
          pos +=3;
        }
        else{
          p++;
          pos++;
        }
      }
      USART_RX_STA = 0;
    }

}

设备展示 {设备展示}

主机端:

从机端:

结语

这就是分享的LC12S模块的使用,如果大家有更好的想法和需求,也欢迎大家分享交流哈。

—END—

推荐阅读

【1】C++的智能指针你了解吗?

【2】嵌入式底层开发的软件框架简述

【3】CPU中的程序是怎么运行起来的 必读

【4】C++的匿名函数(lambda表达式)

【5】阶段性文章总结分析

本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。

原文作者:良知犹存

原文链接:https://www.cnblogs.com/conscience-remain/p/14380598.html

更多推荐

更多
  • Pharo敏捷人工智能-第一部分:神经网络
    Apache CN

  • Pharo敏捷人工智能-第二部分:遗传算法
    Apache CN

  • Pharo敏捷人工智能-# 第三部分:神经进化 第三部分:神经进化
    Apache CN

  • Spark编程-结构化流式编程指南 概述,简单例子,编程模型,使用 Dataset 和 DataFrame 的API,连续处理,额外信息,基本概念,处理 Eventtime 和 Late Data,faulttolerance 语义,创建流式 DataFrame 和流式
  • Spark编程-20 Spark 配置Spark 属性,Environment Variables环境变量,Configuring Logging配置 Logging,Overriding configuration directory覆盖配置目录,Inhe
  • Spark编程-在Mesos上运行Spark 运行原理,安装 Mesos,连接 Spark 到 Mesos,Mesos 运行模式,Mesos Docker 支持,集成 Hadoop 运行,使用 Mesos 动态分配资源,配置,故障排查和调试,从源码安装,第三方软件包,验证,上传 S
  • Spark编程-Running Spark on YARN 启动 Spark on YARN,准备,配置,调试应用,在安全集群中运行,添加其他的 JARs,配置外部的 Shuffle Service,用 Apache Oozie 来运行应用程序,Kerberos 故障排查,使用 Spark Hi
  • Spark编程-Spark 调优 数据序列化,内存调优,其它考虑,,内存管理概论,确定内存消耗,优化数据结构,序列化 RDD 存储,GC优化,并行级别,Reduce任务内存使用,广播大变量,数据局部性, 由于大多数Spark计算都在内存中,所以集群中的任何资源(C
  • Spark编程-Spark Standalone模式 安装 Spark Standalone 集群,手动启动一个集群,集群启动脚本,提交应用程序到集群中,启动 Spark 应用程序,Resource Scheduling资源调度,监控和日志,与 Hadoop 集成,配置网络安全端口,高可用
  • Spark编程-Monitoring and Instrumentation Web 界面,Metrics,高级工具,事后查看,REST API,环境变量,Spark配置选项,API 版本控制策略, 有几种方法来监视 Spark 应用程序:Web UI,metrics 和外部工具。 Web 界面每
  • 近期文章

    更多
    文章目录

      推荐作者

      更多