ไดรเวอร์ STM32 HAL สำหรับโมดูล RFM95 LORAWAN
สำหรับโครงการที่ใช้ CMake (เช่นเมื่อใช้โครงการ STM32Cubemx กับ Clion) คุณสามารถตั้งค่าการตั้งค่าไดรเวอร์เป็น submodule และลิงก์ไปยัง:
add_subdirectory ( "<directory-to-driver>/rfm95" )
target_link_libraries (< target - name > stm32-hal-rfm95)หลังจากเชื่อมต่อโมดูล RFM95 กับไมโครคอนโทรลเลอร์ของคุณผ่าน SPI และเริ่มต้นบัสโดยใช้ลูกบาศก์คุณสามารถใช้ไลบรารีนี้เพื่อโต้ตอบกับโมดูล RFM95 ดังแสดงในตัวอย่างต่อไปนี้ คุณจะต้องจัดการ DIO0, 1 และ 5 ขัดจังหวะ:
int main () {
// Create the handle for the RFM95 module.
rfm95_handle_t rfm95_handle = {
. spi_handle = & hspi1 ,
. nss_port = RFM95_NSS_GPIO_Port ,
. nss_pin = RFM95_NSS_Pin ,
. nrst_port = RFM95_NRST_GPIO_Port ,
. nrst_pin = RFM95_NRST_Pin ,
. device_address = {
0x00 , 0x00 , 0x00 , 0x00
},
. application_session_key = {
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
},
. network_session_key = {
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
},
. receive_mode = RFM95_RECEIVE_MODE_NONE
};
// Initialise RFM95 module.
if (! rfm95_init ( & rfm95_handle )) {
printf ( "RFM95 init failednr" );
}
uint8_t [] data_packet = {
0x01 , 0x02 , 0x03 , 0x4
};
if (! rfm95_send_receive_cycle ( & rfm95_handle , data_packet , sizeof ( data_packet ))) {
printf ( "RFM95 send failednr" );
} else {
printf ( "RFM95 send successnr" );
}
}
void HAL_GPIO_EXTI_Callback ( uint16_t GPIO_Pin )
{
if ( GPIO_Pin == RFM95_DIO0_Pin ) {
rfm95_on_interrupt ( & rfm95_handle , RFM95_INTERRUPT_DIO0 );
} else if ( GPIO_Pin == RFM95_DIO1_Pin ) {
rfm95_on_interrupt ( & rfm95_handle , RFM95_INTERRUPT_DIO1 );
} else if ( GPIO_Pin == RFM95_DIO5_Pin ) {
rfm95_on_interrupt ( & rfm95_handle , RFM95_INTERRUPT_DIO5 );
}
} ฟังก์ชั่น reload_config และ save_config สามารถใช้ในการจัดเก็บและดึงตัวนับเฟรม RX และ TX รวมถึงการกำหนดค่าอื่น ๆ ใน/จากหน่วยความจำที่ไม่ระเหย ตัวอย่างเช่นเมื่อใช้ไลบรารี EEPROM ของฉัน (https://github.com/henriheimann/stm32-hal-eeprom) เพื่อจัดเก็บเคาน์เตอร์เฟรมการใช้งานตัวอย่างอาจมีลักษณะดังต่อไปนี้:
// Forward declaration of the frame counter functions.
static bool reload_config ( rfm95_eeprom_config_t * config );
static void save_config ( const rfm95_eeprom_config_t * config );
// Create the handle for the RFM95 module.
rfm95_handle_t rfm95_handle = {
// ... see example above
. reload_config = reload_config ,
. save_config = save_config ,
};
// Create the EEPROM handle.
eeprom_handle_t eeprom_handle = {
. i2c_handle = & hi2c1 ,
. device_address = EEPROM_24LC32A_ADDRESS ,
. max_address = EEPROM_24LC32A_MAX_ADDRESS ,
. page_size = EEPROM_24LC32A_PAGE_SIZE
};
static bool reload_config ( rfm95_eeprom_config_t * config )
{
return eeprom_read_bytes ( & eeprom_handle , 0x0000 , ( uint8_t * ) config , sizeof ( rfm95_eeprom_config_t ));
}
static void save_config ( const rfm95_eeprom_config_t * config )
{
eeprom_write_bytes ( & eeprom_handle , 0x0000 , ( uint8_t * ) config , sizeof ( rfm95_eeprom_config_t ));
}หากคุณต้องการใช้ความสามารถของไลบรารีในการรับข้อความ downlink ด้วยคำสั่ง MAC ที่สามารถกำหนดค่าอุปกรณ์ปลายทางได้คุณต้องให้นาฬิกาที่แม่นยำและฟังก์ชั่นการหน่วงเวลารวมถึงฟังก์ชั่นอื่น ๆ ตัวอย่างการใช้งานโดยใช้ LPTIM1 ของ STM32L4 อาจมีลักษณะเช่นนี้:
// Forward declaration of the functions.
static uint32_t get_precision_tick ();
static void precision_sleep_until ( uint32_t target_ticks );
static uint8_t random_int ( uint8_t max );
static uint8_t get_battery_level ();
// Create the handle for the RFM95 module.
rfm95_handle_t rfm95_handle = {
// ... see example above
. precision_tick_frequency = 32768 ,
. precision_tick_drift_ns_per_s = 5000 ,
. receive_mode = RFM95_RECEIVE_MODE_RX12 ,
. get_precision_tick = get_precision_tick ,
. precision_sleep_until = precision_sleep_until ,
. random_int = random_int ,
. get_battery_level = get_battery_level
};
volatile uint32_t lptim_tick_msb = 0 ;
static uint32_t get_precision_tick ()
{
__disable_irq ();
uint32_t precision_tick = lptim_tick_msb | HAL_LPTIM_ReadCounter ( & hlptim1 );
__enable_irq ();
return precision_tick ;
}
void HAL_LPTIM_AutoReloadMatchCallback ( LPTIM_HandleTypeDef * hlptim )
{
lptim_tick_msb += 0x10000 ;
}
static void precision_sleep_until ( uint32_t target_ticks )
{
while (true) {
uint32_t start_ticks = get_precision_tick ();
if ( start_ticks > target_ticks ) {
break ;
}
uint32_t ticks_to_sleep = target_ticks - start_ticks ;
// Only use sleep for at least 10 ticks.
if ( ticks_to_sleep >= 10 ) {
// Calculate required value of compare register for the sleep minus a small buffer time to compensate
// for any ticks that occur while we perform this calculation.
uint32_t compare = ( start_ticks & 0xffff ) + ticks_to_sleep - 2 ;
// If the counter auto-reloads we will be woken up anyway.
if ( compare > 0xffff ) {
HAL_SuspendTick ();
HAL_PWREx_EnterSTOP2Mode ( PWR_STOPENTRY_WFI );
HAL_ResumeTick ();
// Otherwise, set compare register and use the compare match interrupt to wake up in time.
} else {
__HAL_LPTIM_COMPARE_SET ( & hlptim1 , compare );
while (! __HAL_LPTIM_GET_FLAG ( & hlptim1 , LPTIM_FLAG_CMPOK ));
__HAL_LPTIM_CLEAR_FLAG ( & hlptim1 , LPTIM_FLAG_CMPM );
__HAL_LPTIM_ENABLE_IT ( & hlptim1 , LPTIM_IT_CMPM );
HAL_SuspendTick ();
HAL_PWREx_EnterSTOP2Mode ( PWR_STOPENTRY_WFI );
HAL_ResumeTick ();
__HAL_LPTIM_DISABLE_IT ( & hlptim1 , LPTIM_IT_CMPM );
}
} else {
break ;
}
// Busy wait until we have reached the target.
while ( get_precision_tick () < target_ticks );
}
static uint8_t random_int ( uint8_t max )
{
return 0 ; // Use ADC other means of obtaining a random number.
}
static uint8_t get_battery_level ()
{
return 0xff ; // 0xff = Unknown battery level.
} รองรับไมโครคอนโทรลเลอร์ STM32L0, STM32L4 และ STM32F4 ส่วนหัว HAL รวมถึงไมโครคอนโทรลเลอร์อื่น ๆ อาจถูกเพิ่มใน rfm95.h