STM32 HAL Driver untuk modul RFM95 Lorawan.
Untuk proyek berbasis CMAKE (misalnya saat menggunakan proyek STM32CUBEMX dengan Clion) Anda dapat misalnya mengatur driver sebagai submodule dan menautkannya:
add_subdirectory ( "<directory-to-driver>/rfm95" )
target_link_libraries (< target - name > stm32-hal-rfm95)Setelah menghubungkan modul RFM95 ke mikrokontroler Anda melalui SPI dan menginisialisasi bus menggunakan Cube, Anda dapat menggunakan pustaka ini untuk berinteraksi dengan modul RFM95 seperti yang ditunjukkan pada contoh berikut. Anda diminta untuk menangani interupsi DIO0, 1 dan 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 );
}
} Fungsi reload_config dan save_config dapat digunakan untuk menyimpan dan mengambil penghitung bingkai RX dan TX serta konfigurasi lainnya dalam/dari memori yang tidak mudah menguap. Misalnya, saat menggunakan perpustakaan EEPROM saya (https://github.com/henriheimann/stm32-hal-eeeprom) untuk menyimpan penghitung bingkai, contoh implementasi mungkin terlihat seperti berikut:
// 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 ));
}Jika Anda ingin menggunakan kemampuan perpustakaan untuk menerima pesan downlink dengan perintah MAC yang dapat mengonfigurasi perangkat akhir, Anda perlu menyediakan fungsionalitas jam presisi dan menunda serta beberapa fungsi lainnya. Contoh implementasi menggunakan LPTIM1 STM32L4 mungkin terlihat seperti ini:
// 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.
} Mikrokontroler STM32L0, STM32L4 dan STM32F4 didukung. Header HAL termasuk untuk mikrokontroler lain dapat ditambahkan dalam rfm95.h .