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

发布者:alpha11最新更新时间:2021-02-09 来源: 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("rn The I2C1 LastEvent is %x rn", I2C_GetLastEvent(I2C1));
  }
  switch(I2C_GetLastEvent(I2C1))
  {
    case I2C_EVENT_MASTER_MODE_SELECT: // 已发送启始条件
    {
 // 七位地址发送
      I2C_Send7bitAddress(I2C1, I2C2_ADDRESS, I2C_Direction_Receiver);
      printf("rn The I2C1 is ready rn");
      break;
    }
    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // 已发送从机地址
    {
      printf("rn The slave address is %x rn", I2C_ReceiveData(I2C1));
      break;
    }
    case (I2C_EVENT_MASTER_BYTE_RECEIVED | (I2C_FLAG_BTF & 0x0f)): // 第一个数据已接收
    {
      // 要接收最后一个字节前先关总线,不然总线锁死
      I2C_GenerateSTOP(I2C1,ENABLE);
      printf("rn The I2C1 has received data2 %x rn", I2C_ReceiveData(I2C1));
      printf("rn The I2C1 is finish rn");
      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("rn The I2C2 LastEvent is %x rn", I2C_GetLastEvent(I2C2));
  }
  switch(I2C_GetLastEvent(I2C2))
  {
    // 收到匹配的地址数据
    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: 
    {
      printf("rn The I2C2 is ready rn");
      I2C_GenerateSTOP(I2C2, DISABLE);
      break;
    }
    case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: //发送数据
    {
      printf("rn The I2C2 transmits is transmitting rn");
      I2C_SendData(I2C2, 0xb6 + Rx_Counter); 
      break;

    }

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

    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
    {

      printf("rn The I2C2 transmits one byte rn");

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

      break;
    }
    case I2C_EVENT_SLAVE_STOP_DETECTED: //收到结束条件
    {
      printf("rn The I2C2 is finish rn");
      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

[1] [2]
关键字:STM32  IIC  从机模式  中断方式  收发数据 引用地址:STM32 IIC 详解 之 stm32 IIC 从机模式(中断方式收发数据)

上一篇:STM32 系统级开发之 ucosIII 或 freeRTOS 事件标志组详解
下一篇:STM32 文件系统 fatfs 移植笔记详解

推荐阅读最新更新时间:2024-11-13 16:51

STM32采用HAL库使用usart_DMA问题
在这里需要理解一个概念就是,使用hal库,首先一定要对标准库中外设的使用,有一个很好的了解,在我这里出现这个原因就是由于对标准库中外设的使用不够了解,导致转移到HAL库,出现各种问题。 本次采用的是HAL库串口2中断的接受,DMA方式发送。 具体想实现的功能是:上位机发送一帧固定的数据(15bit)前面2个字节固定的,在串口中断中,检测到了这个前面2个字节是正确的,则进行数据的处理。处理好数据以后,在采用DMA方式发送出去对应的数据。 出现的问题:每次调用函数这个函数后,下次就不能使用了 MYDMA_USART_Transmit(&UART2_Handler(u8*)USART2_TX_BUF,USART2_REC_LEN
[单片机]
STM32Hal库学习(一)CubeMx学习点亮LED灯
cubemx安装: MDK5安装+破解+pack 言归正传 新建工程选择是STM32型号,进入芯片页面 1.首先必备的SYS和RCC选择外部晶振、配置LED引脚,因板子而异PE5 PE6 2.在clock configuration中配置HCLK 72MHz 3.配置configuration中的GPIO 4.在project中配置路径名称,编译工具 生成工程文件,打开工程,编译文件,创建.hex文件烧录此时LED点亮,再编写一个流水灯程序 感觉直接生成的代码框架有点混乱,之前用的都是标准库,这个就感觉不熟悉还是先创建一个文件夹放自己的程序,然后编写自己的my_system.cpp,my_
[单片机]
STM32Hal库学习(一)CubeMx学习点亮LED灯
如何用flash保存stm32 html的参数
STM32F407由一个Cortex-M4内核,片上flash,片上sram,以及片上外设(uart,I2C,SPI等)组成。 内核通过I,S,D三条数据总线,与总线矩阵相连,对片上flash,片上sram,以及片上外设等进行操作,内核通过I总线获取指令,内核通过D总线进行立即数加载和调试访问,内核通过S总线访问SRAM中的数据,也可以通过该总线获得指令(效率低于I总线)。 并且I总线可以向片内flash,SARM,FSMC取址,而且,STM32F407有三种自举方式,也就是当BOOT1为任意和BOOT0为0时,程序从flash中0x0800 0000 开始自举启动,程序此时开始启动。
[单片机]
STM32复习笔记(十)LCD的介绍和使用方法
声明:本篇文章只是个人知识盲区、知识弱点、重点部分的归纳总结,望各位大佬不喜勿喷。梳理顺序是按照正点原子的视频和文档的实际顺序梳理,转载请注明出处。 作者:sumjess 适用:这个视频我已经看过3遍了,总会有忘记的,所以来写这本书的随手笔记,记录重点、易忘点。该博客可以当做字典,也可以当做笔记。 目前内容:LCD的介绍和使用方法 一、TFTLCD驱动原理-TFTLCD简介: (1)介绍TFTLCD: TFTLCD即薄膜晶体管液晶显示器。它与无源TN-LCD、STN-LCD的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提
[单片机]
<font color='red'>STM32</font>复习笔记(十)LCD的介绍和使用方法
STM32定时器时钟源问题
STM32中有多达8个定时器,其中TIM1和TIM8是能够产生三对PWM互补输出的高级定时器,常用于三相电机的驱动,它们的时钟由APB2的输出产生。其它6个为普通定时器,时钟由APB1的输出产生。 下图是STM32参考手册上时钟分配图中,有关定时器时钟部分的截图: 从图中可以看出,定时器的时钟不是直接来自APB1或APB2,而是来自于输入为APB1或APB2的一个倍频器,图中的蓝色部分。 下面以定时器2~7的时钟说明这个倍频器的作用:当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其它数值(即预分频系数为2、4、8或16)时,这个倍频器起作用,定时器的时钟
[单片机]
<font color='red'>STM32</font>定时器时钟源问题
基于STM32对DS1302的驱动
// 程序名: STM32驱动DS1302 //头文件 #include “stm32f10x.h” #include “usart.h” #define uchar unsigned char #define uint unsigned int ////DS1302引脚定义,可根据实际情况自行修改端口定义 #define RST PAout(5) #define IO PAout(6) #define SCK PAout(7) //DS1302地址定义 #define ds1302_sec_add 0x80 //秒数据地址 #define ds1302_min_add 0x82 //分数据地址 #define ds1302_
[单片机]
STM32与GD32横向对比区别
GD32 是国产单片机,据说开发人员来自ST公司,GD32 也是以 STM32 作为模板做出来的。所以 GD32 和 STM32 有很多地方都是一样的,不过 GD32 毕竟是不同的产品,不可能所有东西都沿用 STM32,有些自主开发的东西还是有区别的。不同的地方如下: 1、内核 GD32 采用二代的 M3 内核,STM32 主要采用一代 M3 内核, ARM 公司的 M3 内核勘误,GD 使用的内核只有 752419 这一个 BUG。 2、主频 使用HSE(高速外部时钟):GD32的主频最大108M,STM32的主频最大72M 使用HSI(高速内部时钟):GD32的主频最大108M,STM32的主频最大64M 主频大意味着单片
[单片机]
<font color='red'>STM32</font>与GD32横向对比区别
stm32下485使用记录
使用STM32做为控制器,板上要求有4个485接口,一个232接口,当232有数据到达时,按条件转发给485,当485有数据到达时,无条件转给232 刚开始编写代码时,由于对485使用不熟悉,不知道该注意哪些,就直接编写程序: 1.配置管脚,这里管脚配置232与485是一样的,但485要用一个管脚的高低电平控制输入输出方向,这里使用使用4个管脚对串口2--串口4控制 2.中断配置,每个串口给与打开对应的中断线,并给与一定的优先级 3.串口配置,这里包含时钟、波特率、8N1等,并选择使用的中断事件,这里所有串口都选用接收中断 232配置和485配置是一样的,无非485是半双工的,需要控制方向,还有一个特别注意的地方,也是我记录这个文档
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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