【STM32 IIC详解】stm32 IIC从机模式(中断方式收发数据)

发布者:size0109最新更新时间:2018-11-26 来源: eefocus关键字:STM32  IIC  从机模式  中断方式  收发数据 手机看文章 扫描二维码
随时随地手机看文章

1、IIC简介

 



第二节代码会用到该部分内容,对于IIC来说,从机是不能主动发送数据的,开始条件都是由主机生成。 


 


 


 


 


1.1、主机发送数据流程

 



  1) 主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始


  2) 主机接着发送一个命令字节。该字节由 7 位的外围器件地址和 1 位读写控制位 R/W组成(此时 R/W=0)


  3) 相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK=0)


  4) 主机收到从机的应答信号后开始发送第一个字节的数据


  5) 从机收到数据后返回一个应答信号 ACK


  6) 主机收到应答信号后再发送下一个数据字节


  7) 当主机发送最后一个数据字节并收到从机的 ACK 后,通过向从机发送一个停止信号P结束本次通信并释放总线。从机收到P信号后也退出与主机之间的通信


 


 


 


 


 


 


1.2、主机接收数据流程

 



  1) 主机发送启动信号后,接着发送命令字节(其中 R/W=1)


  2) 对应的从机收到地址字节后,返回一个应答信号并向主机发送数据


  3) 主机收到数据后向从机反馈一个应答信号


  4) 从机收到应答信号后再向主机发送下一个数据 


  5) 当主机完成接收数据后,向从机发送一个“非应答信号(ACK=1)”,从机收到ASK=1 的非应答信号后便停止发送


  6) 主机发送非应答信号后,再发送一个停止信号,释放总线结束通信


 


 


 


 


 


 


1.3、处理器的I2C模块会在如下所述的情况产生中断信号

 



  RX_UNDER   当处理器通过IC_DATA_CMD寄存器读取接收缓冲器为空时置位


  RX_OVER    当接收缓冲器被填满,而且还有数据从外设发送过来时被置位;缓冲器被填满后接收的数据将会丢失


  RX_FULL    当接收缓冲器达到或者超过IC_RX_TL寄存器中规定的阈值时被置位;当数据低于阈值时标志位将被自动清除


  TX_OVER    当发送缓冲器被填满,而且处理器试图发送另外的命令写IC_DATA_CMD寄存器时被置位


  TX_EMPTY   当发送缓冲器等于或者低于IC_TX_TL寄存器中规定的阈值时被置位;当数据高于阈值时标志位将被自动清除


  TX_ABRT    当i2c模块无法完成处理器下达的命令时被置位,有如下几种原因:


                          * 发送地址字节后没有从机应答


                          * 地址识别成功后主机发送的数据从机没有应答


                          * 当i2c模块只能作为从机时试图发送主机命令


                          * 当模块的RESTART功能被关闭,而处理试图完成的功能必须要RESTART功能开启才能完成


                          * 高速模块主机代码被应答


                          * START BYTE被应答


                          * 模块仲裁失败


                          无论标志位什么时候被置位,发送缓冲器和接收缓冲器的内容都会被刷新 


  ACTIVITY   表明i2c模块正在活动,这个标志位将会一直保持直到用以下4种方式清除:


                          * 关闭i2c


                          * 读取IC_CLR_ACTIVITY寄存器


                          * 读取IC_CLR_INTR寄存器


                          * 系统重启


  即使i2c模块是空闲的,这个标志仍然需要被置位直到被清除,因为这表明i2c总线上有数据正在传输

 

需要用到的:

 

  RD_REQ     当i2c模块作为从机时并且另外的主机试图从本模块读取数据时被置位  


  RX_DONE    当i2c模块作为从机发送数据时,如果主机没有应答则置位;这种情况发生在i2c模块发送最后一个字节数据时,表明传输结束


  STOP_DET   表明i2c总线上产生了STOP信号,无论模块作为主机还是从机


  START_DET  表明i2c总线上产生了START信号,无论模块作为主机还是从机


 


 


 


 


 


 


2、IIC从机中断收发函数

 



// 从机收发函数处理


void I2C1_EV_IRQHandler(void)


{


  __IO uint16_t SR1Register =0;


  __IO uint16_t SR2Register =0;



  SR1Register = I2C1->SR1;           // 通过读取 SR1/2 获取 IIC 状态


  SR2Register = I2C1->SR2;



  // 从机发送


  // 判断IIC是从机模式 - 最低位(MSL = 0)


  if((SR2Register & 0x0001) != 0x0001)


  {


    // ADDR:根据状态判断获取从机IIC地址成功


    if((SR1Register & 0x0002) == 0x0002)


    {


      // 清除标志,准备接收数据


      SR1Register = 0;


      SR2Register = 0;


 TrCount= 0;


    }



//TxE:根据状态标志可以发送数据


if((SR1Register & 0x0080) == 0x0080)


{


 SR1Register = 0;


      SR2Register = 0;


 I2C1->DR =TrCount ++;


}


//STOPF:监测停止标志


if((SR1Register & 0x0010) == 0x0010)


{


 I2C1->CR1 |= CR1_PE_Set;


      SR1Register = 0;


      SR2Register = 0;


 TrCount= 5;


}


//TIME_OUT


if((SR1Register & 0x4000) == 0x4000)


{


 I2C1->CR1 |= CR1_PE_Set;


 SR1Register = 0;


      SR2Register = 0;


}


  }  

  

  // IIC从机接收


  // 判断IIC是从机模式 - 最低位(MSL = 0)


  if((SR2Register &0x0001) != 0x0001)


  {


    // 收到主机发送的地址:(ADDR = 1: EV1) 


    if((SR1Register & 0x0002) == 0x0002)


    {


      // 清除标志,准备接受数据


      SR1Register = 0;


      SR2Register = 0;


      Rx_Idx = 0;


    }

    

    // 接收数据 (RXNE = 1: EV2)


    if((SR1Register & 0x0040) == 0x0040)


    {


      Buffer_Rx[Rx_Idx++] = I2C1->DR;


      SR1Register = 0;


      SR2Register = 0;


    }

    

    // 监测停止条件 (STOPF =1: EV4) 


    if(( SR1Register & 0x0010) == 0x0010)


    {


      I2C1->CR1 |= CR1_PE_Set;


      SR1Register = 0;


      SR2Register = 0;


      Flag_RcvOK = 1;                         


    }


  }


}


 


 


 


 


 


 


3、代码参考实例

 



//stm32f10x_it.c



#include "stm32f10x_it.h"


#include "stdio.h"



extern u32 BufferSize ;


extern u8 I2C1_ADDRESS ;


extern u8 I2C2_ADDRESS ;


extern vu8 I2C1_Buffer_Tx[];


extern vu8 I2C2_Buffer_Rx[];


vu32 Tx_Counter = 0;


vu32 Rx_Counter = 0;


vu32 show_counter1 = 0;


vu32 show_counter2 = 0;



// I2C1 作为主机,用于中断接收从机数据


void I2C1_EV_IRQHandler(void)


{


  show_counter1++;


  if(show_counter1 > 1000000)


  {


    show_counter1 = 0;


    printf("\r\n The I2C1 LastEvent is %x \r\n", I2C_GetLastEvent(I2C1));


  }


  switch(I2C_GetLastEvent(I2C1))


  {


    case I2C_EVENT_MASTER_MODE_SELECT: // 已发送启始条件


    {


 // 七位地址发送


      I2C_Send7bitAddress(I2C1, I2C2_ADDRESS, I2C_Direction_Receiver);


      printf("\r\n The I2C1 is ready \r\n");


      break;


    }


    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // 已发送从机地址


    {


      printf("\r\n The slave address is %x \r\n", I2C_ReceiveData(I2C1));


      break;


    }


    case (I2C_EVENT_MASTER_BYTE_RECEIVED | (I2C_FLAG_BTF & 0x0f)): // 第一个数据已接收


    {


      // 要接收最后一个字节前先关总线,不然总线锁死


      I2C_GenerateSTOP(I2C1,ENABLE);


      printf("\r\n The I2C1 has received data2 %x \r\n", I2C_ReceiveData(I2C1));


      printf("\r\n The I2C1 is finish \r\n");


      break;


    }


    case 0x40:


    {


      // 接收了两个同样的数据,没有这个释放不了 RXNE


      I2C_ReceiveData(I2C1);


    }


default: {break;}


  }


}



// I2C2 用于从机发送数据到主机


void I2C2_EV_IRQHandler(void)


{


  show_counter2++;


  if(show_counter2 > 100000)


  {


    show_counter2 = 0;


    printf("\r\n The I2C2 LastEvent is %x \r\n", I2C_GetLastEvent(I2C2));


  }


  switch(I2C_GetLastEvent(I2C2))


  {


    // 收到匹配的地址数据


    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: 


    {


      printf("\r\n The I2C2 is ready \r\n");


      I2C_GenerateSTOP(I2C2, DISABLE);


      break;


    }


    case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: //发送数据


    {


      printf("\r\n The I2C2 transmits is transmitting \r\n");


      I2C_SendData(I2C2, 0xb6 + Rx_Counter); 


      break;


 


 


 


 


    }


 


   // 发送数据,要发送,不然锁死,不过 master 没收到


    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:


    {


      printf("\r\n The I2C2 transmits one byte \r\n");


     I2C_SendData(I2C2, 0xb6 + (Rx_Counter++));


      break;


    }


    case I2C_EVENT_SLAVE_STOP_DETECTED: //收到结束条件


    {


      printf("\r\n The I2C2 is finish \r\n");


      I2C_ClearFlag(I2C2,I2C_FLAG_STOPF);


      I2C_GenerateSTOP(I2C2, ENABLE);


      break;


    }


    default: {break;}


  }


}



/*----------------------------------------------------------------------------------------------------


名称: I2C 测试 24C02 测试


编写: mingzhang.zhao


内容:测试 stm32f103vct6 的硬件 I2C 实现中断收发数据


注意事项:


1.USART1: PA9 为 TX, PA10 为 RX


I2C1: PB6 为 SCL, PB7 为 SDA


I2C2: PB10 为 SCL, PB11 为 SDA


----------------------------------------------------------------------------------------------------*/


#include "stm32f10x.h"


#include "stdio.h"


#define PRINTF_ON 1


void RCC_Configuration(void);void GPIO_Configuration(void);


void USART_Configuration(void);


void I2C_Configuration(void);


void NVIC_Configuration(void);


void Delay(__IO uint32_t t);


u8 I2C1_ADDRESS = 0x30; //7 位 I2C 地址


u8 I2C2_ADDRESS = 0x31;


#define Size 4


vu8 I2C1_Buffer_Tx[Size] = {1,2,3,4};


vu8 I2C2_Buffer_Rx[Size] = {0};


u32 BufferSize = Size ;



int main(void)


{


  RCC_Configuration();


  GPIO_Configuration();


  USART_Configuration();


  I2C_Configuration();


  NVIC_Configuration();


  I2C_GenerateSTART(I2C1,ENABLE);


  while(1)


  {


    Delay(1000);


    I2C_GenerateSTART(I2C1,ENABLE); //I2C1 循环读取数据


  }


}



// 初始化和配置相关


void I2C_Configuration(void)


{


  I2C_InitTypeDef I2C_InitStructure;


  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;


  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;


  I2C_InitStructure.I2C_OwnAddress1 = I2C1_ADDRESS;


  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;


  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;


  I2C_InitStructure.I2C_ClockSpeed = 200000;I2C_Init(I2C1,&I2C_InitStructure);


  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;


  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;


  I2C_InitStructure.I2C_OwnAddress1 = I2C2_ADDRESS;


  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;


  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;


  I2C_InitStructure.I2C_ClockSpeed = 200000;


  I2C_Init(I2C2,&I2C_InitStructure);


  I2C_ITConfig(I2C1,I2C_IT_EVT|I2C_IT_BUF,ENABLE);


  I2C_ITConfig(I2C2,I2C_IT_EVT|I2C_IT_BUF,ENABLE);


  I2C_Cmd(I2C1,ENABLE);


  I2C_Cmd(I2C2,ENABLE);


}



void NVIC_Configuration(void)


{


  NVIC_InitTypeDef NVIC_InitStructure;


  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);


  NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;


  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;


  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;


  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;


  NVIC_Init(&NVIC_InitStructure);


  NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;


  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;


  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;


  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;


  NVIC_Init(&NVIC_InitStructure);


}



void GPIO_Configuration(void)


{


  GPIO_InitTypeDef GPIO_InitStructure;


  //初始化 I2C1GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;


  GPIO_Init(GPIOB , &GPIO_InitStructure);


  //初始化 I2C2


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;


  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;


  GPIO_Init(GPIOB , &GPIO_InitStructure);


  //初始化 USART1


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;


  GPIO_Init(GPIOA , &GPIO_InitStructure);


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;


  GPIO_Init(GPIOA , &GPIO_InitStructure);


}



void RCC_Configuration(void)


{


  /* 定义枚举类型变量 HSEStartUpStatus */


  ErrorStatus HSEStartUpStatus;


  /* 复位系统时钟设置*/


  RCC_DeInit();


  /* 开启 HSE*/

 

 RCC_HSEConfig(RCC_HSE_ON);


  /* 等待 HSE 起振并稳定*/


  HSEStartUpStatus = RCC_WaitForHSEStartUp();


  /* 判断 HSE 起是否振成功,是则进入 if()内部 */


  if(HSEStartUpStatus == SUCCESS)


  {


  /* 选择 HCLK(AHB)时钟源为 SYSCLK 1 分频 */


  RCC_HCLKConfig(RCC_SYSCLK_Div1);


  /* 选择 PCLK2 时钟源为 HCLK(AHB) 1 分频 */


  RCC_PCLK2Config(RCC_HCLK_Div1);


  /* 选择 PCLK1 时钟源为 HCLK(AHB) 2 分频 */RCC_PCLK1Config(RCC_HCLK_Div2);


  /* 设置 FLASH 延时周期数为 2 */

 

 FLASH_SetLatency(FLASH_Latency_2);


  /* 使能 FLASH 预取缓存 */


  FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);


  /* 选择锁相环(PLL)时钟源为 HSE 1 分频, 倍频数为 9,则 PLL 输出频率为 8MHz


  * 9 = 72MHz */


  RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);


  /* 使能 PLL */


  RCC_PLLCmd(ENABLE);


  /* 等待 PLL 输出稳定 */


  while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);


  /* 选择 SYSCLK 时钟源为 PLL */


  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);


  /* 等待 PLL 成为 SYSCLK 时钟源 */


  while(RCC_GetSYSCLKSource() != 0x08);


  }


  /* 打开 APB2 总线上的 GPIOA 时钟*/

  

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB


  2Periph_USART1, ENABLE);


  //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1|RCC_APB1Periph_I2C2,ENABLE);

  

//RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Pe

 

 riph_WWDG|RCC_APB1Periph_SPI2, ENABLE);


}



void USART_Configuration(void)


{


  USART_InitTypeDef USART_InitStructure;


  USART_ClockInitTypeDef 

USART_ClockInitStructure;USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;

 

 USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;


  USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;


  USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;


  USART_ClockInit(USART1 , &USART_ClockInitStructure);


  USART_InitStructure.USART_BaudRate = 9600;


  USART_InitStructure.USART_WordLength = USART_WordLength_8b;


  USART_InitStructure.USART_StopBits = USART_StopBits_1;


  USART_InitStructure.USART_Parity = USART_Parity_No;


  USART_InitStructure.USART_HardwareFlowControl =


  USART_HardwareFlowControl_None;


  USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;


  USART_Init(USART1,&USART_InitStructure);


  USART_Cmd(USART1,ENABLE);


}



void Delay(__IO uint32_t t)


{


  while(t--);


}


#if PRINTF_ON


int fputc(int ch,FILE *f)


{


  USART_SendData(USART1,(u8) ch);


  while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);


  return ch;


}


#endif


--------------------- 


作者:liwei16611 


来源:CSDN 


原文:https://blog.csdn.net/liwei16611/article/details/75258222 


版权声明:本文为博主原创文章,转载请附上博文链接!


关键字:STM32  IIC  从机模式  中断方式  收发数据 引用地址:【STM32 IIC详解】stm32 IIC从机模式(中断方式收发数据)

上一篇:STM32 I2C从机发送数据_中断方式
下一篇:STM32L151 I2C从机实现

推荐阅读最新更新时间:2024-03-16 16:18

STM32学习笔记----SysTick
SysTick时钟为HCKL的8分频,故如果HCLK时钟为72MHz,SysTick- LOAD的值为7200的话,则SysTick 1ms中断 一次。如果屏蔽全局中断的话,则STSTICK不能这用。 ---------------------------------------------------------------------------------------------------- 例: //SysTick 配置 if (SysTick_Config(SystemFrequency / 1000)) // (72MHz/1000)*SYSCL
[单片机]
STM32移植USB驱动总结
//=========================By xiaowei /* */ //========================= 1、硬件介绍 1、SGM7227,USB高速切换开关,OE是芯片使能,低电平才能使总线导通; S脚是切换控制; USB协议 https://segmentfault.com/a/1190000015995506 2、软件移植 移植文件分析 stm32自带USB接口,OTG-FS(全速)和OTG-HS(高速),因为stm32f4只带有高速PHY,想使用高速模式,就需要外扩高速PHY,在此为USB3300。 系统配置一个Device端口,一个Host端口; Device端
[单片机]
<font color='red'>STM32</font>移植USB驱动总结
stm32软件模拟I2C
一 概述 很多人都知道stm32的硬件I2C存在BUG,现在我们通过软件模拟时序的办法来实现I2C。 使用软件模拟I2C主要是方便程序的移植,只需要更改一下相应的IO端口即可。 二 软件模拟实现 1 起始信号 void i2c_Start(void) { macI2C_SDA_1(); //首先确保SDA和SCL都是高电平 macI2C_SCL_1(); i2c_Delay(); macI2C_SDA_0(); //先拉低SDA i2c_Delay(); macI2C_SCL_0(); //在拉低SCL i2c_Delay(); } 2 总
[单片机]
STM32开发笔记85: SX1268驱动程序设计(芯片唤醒)
单片机型号:STM32L053R8T6 本系列开发日志,将详述SX1268驱动程序的整个设计过程,本篇介绍芯片唤醒驱动程序。 一、RxDutyCycle模式 在讲述本篇内容之前,我们先来看一下SX1268的一种模式RxDutyCycle,译为中文为接收占空比模式。其可使用SetRxDutyCycle命令进入RxDutyCycle模式,我们来看一下该命令的详细解释。 该命令具有2个参数,从字面的意思可以看出,1个是指接收周期时间,另1个是指睡眠周期时间。我们可分析出,该命令是在RX模式和SLEEP模式之间自动转换的一种模式,其目的是为了节省芯片功耗。如果在使能外部中断后,则单片机可以进入睡眠态,SX1268大部分时间也是
[单片机]
<font color='red'>STM32</font>开发笔记85: SX1268驱动程序设计(芯片唤醒)
STM32开发笔记83: SX1268驱动程序设计(芯片复位)
单片机型号:STM32L053R8T6 本系列开发日志,将详述SX1268驱动程序的整个设计过程,本篇介绍芯片复位驱动程序。 一、数据手册 1、NRESET是芯片第15引脚,低有效。 2、通过15引脚NREST,可以达到完整的芯片复位。复位后,会执行标准的校准程序,先前的内容将丢失。复位最短时间为50us,给100us较为合适。 3、这张图是芯片各个模式的引脚的状态表,可以看到除复位模式外,其余模式NREST引脚的状态都为IN PU,其意思是输入上拉,其上拉值为50K。 二、程序 1、由于其内部上来,我们可以给出低功耗的程序,不将单片机控制NREST的引脚设置为输出,而设置为analog引脚,程序如下: c
[单片机]
<font color='red'>STM32</font>开发笔记83: SX1268驱动程序设计(芯片复位)
STM32用keil5调试程序出现 Error:Flash Download Failed-"Cortex-M3"解决方案
一 目的:装好keil MDK 想用 在线调试 二 背景:开发环境 keil MDK 422 三 准备: 1 keil MDK 安装文件夹ARMSegger里是否有三个动态连接表 2 程序编译通过 3 jlink驱动安装好(我安装的是408版本) 四 操作步骤: 1 2 3 5 然后一路OK过去 就可以了。 6 点 进入到在线调试届满 进行调试。 注:如果没有进行第五步(根据芯片选择flash容量)会报错 Error: Flash download failed- Cortex-M3 。 、、、、、、、、、、、、、、、、、、
[单片机]
<font color='red'>STM32</font>用keil5调试程序出现 Error:Flash Download Failed-
STM32 I2C AT24C02驱动
如果搞过51的I2C的同志,再来看看STM32的I2C驱动,一定有相见恨晚的感觉。STM32自带I2C硬件模块,再配合ST的官方库函数,I2C在STM32这里可以玩得如火的地步。这里的这个I2C驱动算是很完整了的,可以直接拿来用到项目开发中去。好,不废话,上图: 工程结构图: 1、main.c #include stm32f10x.h #include usart1.h #include led.h #include i2c_at24c02.h #include struct Contact{ u8 Name ; //姓名 u8 Phone ; //电话
[单片机]
在单片机上实现动态加载功能
本项目是一个在单片机(如:STM32)上实现动态加载功能的函数库,与Windows中的dll,Linux中的so类似,可以将代码动态地从其他的存储介质,动态加载到RAM中。 软件架构 本项目文件夹有三个,其中common存储了用于生成可重定位的.axf文件的工程与动态加载器工程交互用的函数,src提供动态加载器的源码,rel_axf_project_template提供了一个简单的可重定位的.axf文件的工程示例,example.c是一个简单的使用示例,所有文件的主要功能如下: /common/dl_extern_lib.h 描述了app程序用于调用host程序的函数向量表的基地址,以及相关的一些宏定义 /common/dl_
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved