understand “extern” in C

-apply to C variables and functions
-extends the visibility of the C variables and C functions

difference between declaration and definition
declaration  - exist somewhere in the program but the memory is not allocated 
                      (we could know the types from declarations)
definition - declaration + allocate memory for that variable/function
a variable/function can be declared any number of times but it can be defined one once
why? (cannot have two locations of the same variable/function)

extern

function

int foo(int arg1, char arg2); //extern exists by default
extern int foo(int arg1, char arg2);

The above two lines will be treated the same by C compiler since C compiler will add extern when compiling the first line.
Declaration can exist in several files and any files with the function declaration can use the function.
How C compiler works? By knowing the declaration of the function, C compiler knows that the definition of the function exists and it goes ahead to compile the program.
*extern implicit for C function


variable

extern int var;     //declaration only
int var;                //definition   
*extern explicitly for C variable

Conclusion

1.declaration can be done any number of times but definition only once
2.”extern” is used to extend the visibility of variables/functions
3.Since functions are visible through out the program by default, the use of extern is redundant.
4.When extern is used for a variable, it’s declared only
5.extern with initialization is allowed but with warning

One sentence: tell the program to find defintions in other files

//variable examples

#include<iostream>
using namespace std;
int var;
int main(){
	var =10;
	return 0;
}


// compile successfully <- defined and use (defined and not use is trivial)
// var is globally defined


extern int var;
int main(void)
{
  return 0;
}


//compile successfully <- declared only but not use
//var is globally declared


extern int var;
int main(void)
{
 var = 10;
 return 0;
}


//throw error <- declared only and use
//var is globally declared but not defined(no memory allocated for the variable)


#include "somefile.h"
extern int var;
int main(void)
{
 var = 10;
 return 0;
}


//compile successfully <- defined and use
//var is globally defined if somefile.h has the definition of var


extern int var = 0;
int main(void)
{
 var = 10;
 return 0;
}
// error <- declared with initialization
//from compiler: warning: 'extern' variable has an initializer [-Wextern-initializer]

Reference: https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

### STM32 I2C Slave HAL Library Example Code and Documentation For configuring the STM32 as an I2C slave using the HAL library, it is essential to understand how the hardware abstraction layer (HAL) simplifies interaction with peripherals like I2C. The configuration primarily revolves around setting up the necessary parameters within STM32CubeMX or directly through code initialization functions provided by the HAL library. #### Configuration Using STM32CubeMX To set up a project where STM32 acts as an I2C slave, one should start from STM32CubeMX which facilitates easy peripheral setup including pin configurations, clock settings, and interrupt handling[^1]. After generating the initial code structure via CubeMX, modifications are made mostly inside `main.c` file along with callback implementations for event processing during communication sessions. #### Sample Initialization Function Below shows part of what would be generated automatically when configuring I2C interface in slave mode: ```c /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_I2C1_Init(void); int main(void) { /* Initialize all configured peripherals & users */ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); // GPIO Initialization Function MX_I2C1_Init(); // I2C Peripheral Initialization while (1) { // Main loop tasks here... } } // This function configures the I2C1 peripheral. static void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.Timing = 0x20909CEC; // Timing parameter depends on system frequency hi2c1.Init.OwnAddress1 = SLAVE_ADDRESS;// Define your own address here hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } } ``` The above snippet demonstrates basic initialization steps required before entering into application-specific logic such as receiving data over I2C bus. Note that specific timing values may vary depending upon actual microcontroller model used and its operating conditions. #### Handling Data Reception Events When acting as a slave device, responding correctly to master requests involves implementing appropriate callbacks defined under HAL API. Here’s an example showing how these handlers might look: ```c extern uint8_t ReceivedDataBuffer[RECV_BUFFER_SIZE]; volatile int RecvIndex = 0; /** * @brief Handle Master reception request complete callback */ void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c){ // Process received bytes stored temporarily in buffer variable printf("Received %d byte(s): ",RecvIndex); for(int i=0;i<RecvIndex;i++){ putchar(ReceivedDataBuffer[i]); } putchar('\n'); // Reset index ready for next transfer RecvIndex = 0; } /** * @brief Handle Memory read/write operation completion */ void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c){ // Implement any post-transmission actions needed after writing memory location } /** * @brief Called at end of each successfully completed transaction initiated by this node being addressed as target/slave */ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c,uint8_t TransferDirection,unsigned char AddrMatchCode){ // Prepare buffers based on whether we're expecting reads/writes now if(TransferDirection == HAL_I2C_DIRECTION_TRANSMIT){ // Setup transmit buffer pointer etc.. }else{ // RECEIVE direction memset((char*)ReceivedDataBuffer,'\0',sizeof(ReceivedDataBuffer)); } } ``` These snippets provide insight into managing events triggered throughout different stages of communications between devices connected via I2C protocol. By registering custom handler routines linked against standard interfaces offered by HAL framework, developers gain flexibility tailoring behavior according to particular requirements without delving too deeply into low-level details concerning register manipulation.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值