gaoyang9992006 发表于 2021-11-19 21:39

为了遥控的更远,我用PIC18F16Q41驱动CC1101收发数据

本帖最后由 gaoyang9992006 于 2021-11-19 21:42 编辑

#技术资源# #申请原创# @21小跑堂
之前我做了蓝牙遥控的小车,这里为了拓展遥控的距离,我准备采用CC1101模块进行拓展距离。
我之所以选择PIC或AVR是出于MCC的快捷可视化配置,让我不用去了解单片机的寄存器即可轻松快速实现设计目标。

端口的配置上我使用MCC进行配置,这样就不需要在移植代码中实现一堆的初始化了,非常方便。
PIC和AVR都具备内部上拉电阻,在需要配置为输入的端口,使用上拉稳定电平是非常容易的。
另外MCC的端口可定制新名字功能,非常有助于我们移植代码,防止多了就容易乱。

在这个表里,非常容易初始化代码,可以设置是否上拉,另外可以指定初始化后是否默认高电平。

利用MCC生成的代码我们直接就可以用于移植了。比如下面的串口收发
/**
* @brief :串口发送数据
* @param :
*                        @TxBuffer:发送数据首地址
*                        @Length:数据长度
* @NOTE:无
* @retval:无
*/
void drv_uart_tx_bytes( uint8_t* TxBuffer, uint8_t Length )
{
      while( Length-- )
      {
                UART1_Write(*TxBuffer);
                TxBuffer++;
      }
}

/**
* @brief :串口接收数据
* @param :
*                        @RxBuffer:发送数据首地址
* @NOTE:无
* @retval:接收到的字节个数
*/
uint8_t drv_uart_rx_bytes( uint8_t* RxBuffer )
{
      uint8_t l_RxLength = 0;
      uint16_t l_UartRxTimOut = 0x7FFF;
      
      while( l_UartRxTimOut-- )                        //等待查询串口数据
      {

                if( UART1_is_rx_ready())
                {
            *RxBuffer = UART1_Read();
            RxBuffer++;
            l_RxLength++;
                        l_UartRxTimOut = 0x7FFF;      //接收到一个字符,回复等待时间
                }
                if( 100 == l_RxLength )
                {
                        break;                        //不能超过100个字节
                }
      }
      
      return l_RxLength;                                        //等待超时,数据接收完成
}
以及SPI的端口操作映射,只需要在对应的头文件修改成MCC生成的代码即可
#define __USE_SOFT_SPI_INTERFACE__


#define spi_set_nss_high( )                        NSS_SetHigh()                                       //片选置高
#define spi_set_nss_low( )                        NSS_SetLow()      //片选置低


#ifdef __USE_SOFT_SPI_INTERFACE__                        /** 只有使用软件SPI才需要的封装 */               


#define spi_set_clk_high( )                        SCL_SetHigh()                                        //时钟置高
#define spi_set_clk_low( )                        SCL_SetLow()         //时钟置低

#define spi_set_mosi_hight( )                MOSI_SetHigh()                                        //发送脚置高
#define spi_set_mosi_low( )                        MOSI_SetLow()      //发送脚置低

#define spi_get_miso( )                              MISO_GetValue() // 若相应输入位为低则得到0,相应输入位为高则得到1因为开发板只有一个可配置的LED,所以这里我就只使用了红色的
void drv_led_on( LedPortType LedPort )
{
      if( LED_RED == LedPort )      //LED_RED
      {
                RED_LED_SetLow();      //红色LED引脚置低,红色LED亮
      }
      else                                                //LED_BLUE
      {
                ;//绿色LED引脚置低,蓝色LED亮
      }
      
}

/**
* @brief :LED灭
* @param :
*                        @LedPort:LED选择,红色或绿色
* @note:无
* @retval:无
*/
void drv_led_off( LedPortType LedPort )
{
      if( LED_RED == LedPort )      //LED_RED
      {
                RED_LED_SetHigh();                //红色LED引脚置高,红色LED灭
      }
      else                                                //LED_BLUE
      {
                ;      //绿色LED引脚置高,蓝色LED灭
      }
      
}

/**
* @brief :LED闪烁
* @param :
*                        @LedPort:LED选择,红色或绿色
* @note:无
* @retval:无
*/
void drv_led_flashing( LedPortType LedPort )
{
      //引脚翻转,LED闪烁
      if( LED_RED == LedPort )
      {
                RED_LED_Toggle();      
      }
      else
      {
                ;
      }
}按钮的使用,也是非常容易,直接使用MCC生成的函数
/**
* @brief :按键查询
* @param :无
* @note:无
* @retval:
*                        0:按键没有按下
*                        1:检测到按键动作
*/
uint8_t drv_button_check( void )
{
      if( 0x00 == (BUTTON_GetValue() & 0x01 ))                //检测按键输入状态
      {
                drv_delay_ms( 40 );                        //消抖
                if( 0x00 == (BUTTON_GetValue()& 0x01 ))
                {
                        return 1;                              //按键按下,返回按键状态
                }
      }
      
      return 0;
}cc1101库函数里的相关操作也是使用MCC的生成函数替换
#define CC1101_SET_CSN_HIGH( )                        spi_set_nss_high( )
#define CC1101_SET_CSN_LOW( )                        spi_set_nss_low( )

#define CC1101_GET_GDO0_STATUS( )                (( GDO0_GetValue()) == 0x00 ) ? 0 : 1      //GDO0状态
#define CC1101_GET_GDO2_STATUS( )                (( GDO2_GetValue()) == 0x00 ) ? 0 : 1      //GDO2状态


至此,我们基本上没去了解关于寄存器的任何知识,就完成了移植。

最后奉上main.c的完整内容

#include "mcc_generated_files/mcc.h"
#include"drv_periph/inc/drv_CC1101.h"
#include"drv_mcu/inc/drv_button.h"
#include"drv_mcu/inc/drv_delay.h"
#include"drv_mcu/inc/drv_spi.h"
#include"drv_mcu/inc/drv_uart.h"
#include"drv_mcu/inc/drv_led.h"
#include"string.h"

#define      __CC1101_TX_TEST__      
/*
                         Main application
*/
const char *g_Text = "Hello I'm PIC18F16Q41";
uint8_t g_TxMode = 0, g_UartRxFlag = 0;
uint8_t g_UartRxBuffer[ 100 ] = { 0 };
uint8_t g_RF24L01RxBuffer[ 32 ] = { 0 };
/** 发送模式定义 */
enum
{
      TX_MODE_1 = 0,                //发送模式1,发送固定的字符串
      TX_MODE_2                        //发送模式2,发送串口接收到的数据
};

void main(void)
{
    uint8_t i = 0;
    // Initialize the device
    SYSTEM_Initialize();

    // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
    // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
    // Use the following macros to:

    // Enable the Global Interrupts
    //INTERRUPT_GlobalInterruptEnable();

    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();
    printf("Hello\n");
            //CC1101初始化
      CC1101_Init( );
      for( i = 0; i < 6; i++ )
      {
                led_red_flashing( );
                led_green_flashing( );
                drv_delay_ms( 500 );
      }
   
#ifdef      __CC1101_TX_TEST__      
      
      //按键初始化
      drv_button_init( );

      while( 1 )      
      {
                //模式切换
                //Demo程序默认为发送模式1,即发送固定字符串“Hello I'm PIC18F16Q41"”,可以通过按键切换到发送模式2,即通过串口发送数据,按键的作用就是切换发送模式1 2
                //如果在程序移植过程中不需要两种发送模式,删除下面 if 语句程序块和按键初始化程序即可
                if( BUTOTN_PRESS_DOWN == drv_button_check( ))
                {
                        g_TxMode = 1 - g_TxMode;                //模式会在 TX_MODE_1( 0 ),TX_MODE_2( 1 )之间切换
                        
                        //状态显示清零
                        led_green_off( );
                        led_red_off( );
                        
                        if( TX_MODE_1 == g_TxMode )
                        {
                              for( i = 0; i < 6; i++ )               
                              {
                                        led_red_flashing( );      //固定发送模式,红灯闪烁3次
                                        drv_delay_ms( 500 );               
                              }
                        }
                        else
                        {
                              for( i = 0; i < 2; i++ )
                              {
                                        led_red_flashing( );      //串口发送模式,绿灯闪烁3次
                                        drv_delay_ms( 500 );
                              }
                        }
                }

                //如果在程序移植过程中不需要两种发送模式,删除上面 if 语句程序块和按键初始化程序即可
                //模式切换

               
                //发送
                if( TX_MODE_1 == g_TxMode )
                {
                        CC1101_Tx_Packet( (uint8_t *)g_Text, strlen(g_Text) , ADDRESS_CHECK );                //模式1发送固定字符,1S一包
                        drv_delay_ms( 1000 );      
                        led_red_flashing( );                        
                }
                else
                {      
                        //查询串口数据
                        i = drv_uart_rx_bytes( g_UartRxBuffer );
                        
                        if( 0 != i )
                        {
                              CC1101_Tx_Packet( g_UartRxBuffer, i , ADDRESS_CHECK );
                              led_red_flashing( );
                        }
                }
      }   
#else
/*
接收
*/
    while (1)
    {
//      DELAY_milliseconds(1000);
//      printf("Hello World \n");

      CC1101_Clear_RxBuffer( );
                CC1101_Set_Mode( RX_MODE );

                i = CC1101_Rx_Packet( g_RF24L01RxBuffer );                //接收字节
                if( 0 != i )
                {
                        led_red_flashing( );
                        drv_uart_tx_bytes( g_RF24L01RxBuffer, i );      //输出接收到的字节
            printf("\n");
                }
    }
#endif   
}
/**
End of File
*/


gaoyang9992006 发表于 2021-11-19 21:47

最后请注意我设置上拉电阻使能的两个输入管脚,如果你的单片机不支持内部上拉电阻,需要外置一个,不然嘿嘿,你就找不到问题出哪儿了,就是收发不成功。。。

lcczg 发表于 2021-11-24 16:15

内部的上拉电阻还是很有用的

gaoyang9992006 发表于 2021-11-24 18:21

lcczg 发表于 2021-11-24 16:15
内部的上拉电阻还是很有用的

是的,并非所有的单片机都具备内部上拉,不然关键时候真的会掉链子。

740071911 发表于 2021-11-26 13:15

传一个视频看看呢

gaoyang9992006 发表于 2021-11-26 13:47

740071911 发表于 2021-11-26 13:15
传一个视频看看呢

出差去了,在徐州,突发疫情,被困在这了,估计要一个月才能回去。视频是看测试通信距离的视频,还是看软件编写过程的视频

493326732 发表于 2021-11-27 12:44

666啊

493326732 发表于 2021-11-27 15:19

有相关的视频教程吗   

zydl123 发表于 2021-11-27 19:43

测试过吗?最远距离是多少

cjseng 发表于 2021-11-28 12:19

zydl123 发表于 2021-11-27 19:43
测试过吗?最远距离是多少

天线匹配良好的话,100米还是有的

gaoyang9992006 发表于 2021-11-28 12:25

cjseng 发表于 2021-11-28 12:19
天线匹配良好的话,100米还是有的

我跑了一条街,400米外测试,信号完好,收发正常。更远没去测。

wangchangwenqq 发表于 2021-11-28 15:26

准备弄一个通过蓝牙收发,

梅花香自123 发表于 2021-11-28 23:40

很详细的开发资料6666

740071911 发表于 2021-11-29 08:46

gaoyang9992006 发表于 2021-11-26 13:47
出差去了,在徐州,突发疫情,被困在这了,估计要一个月才能回去。视频是看测试通信距离的视频,还是看软 ...

是遥控小车跑起来的视频,软件编写视频那要很长世间吧

pzsh 发表于 2021-11-29 13:55

gaoyang9992006 发表于 2021-11-28 12:25
我跑了一条街,400米外测试,信号完好,收发正常。更远没去测。

这么远的距离

gaoyang9992006 发表于 2021-11-29 22:38

pzsh 发表于 2021-11-29 13:55
这么远的距离

无障碍应该可以直接800米到1000米。

gaoyang9992006 发表于 2021-11-30 11:25

740071911 发表于 2021-11-29 08:46
是遥控小车跑起来的视频,软件编写视频那要很长世间吧

关注我的抖音,抖音发了视频,抖音号:
123237318

怀揣少年梦 发表于 2021-12-3 13:59

距离这么远啊,请问用了多大增益的天线?

hi0712 发表于 2021-12-3 14:26

复杂了复杂了

kyzhd 发表于 2021-12-3 14:41

gaoyang9992006 发表于 2021-11-26 13:47
出差去了,在徐州,突发疫情,被困在这了,估计要一个月才能回去。视频是看测试通信距离的视频,还是看软 ...

我大徐州也有疫情了,楼主注意安全啊。
页: [1] 2
查看完整版本: 为了遥控的更远,我用PIC18F16Q41驱动CC1101收发数据