对串口接收FIFO处理机制的解读

李肖遥 2022-09-13 22:08
    关注、星标公众号,直达精彩内容

素材来源:https://blog.csdn.net/weixin_44386927/article/details/124626454

整理:技术让梦想更伟大 | 李肖遥



一、FIFOFIFO

First Input First Output的缩写,先入先出队列。

使用的场景:一般是在不同的时钟域之间的数据传输(简单理解即:一个(读\写)快,另外的一个(读\写)慢的场景中。)

本质操作:就是将收的数据存储的一个线性的数组中,通过指针指向该数组的自加1(偏移)来遍历数据,达到读取或者写入的目的。

作用:起到缓冲环节,可防止数据的丢失。

对数据量大的进行存储,避免频繁的总线操作。并且可满足dma的操作。

在fifo中需要理解连个重要成员:

宽度:指一次写读操作的数据位数

深度:存储多少个宽度的数据。(如:存储8个16位宽的数据)。

第一类、FIFO处理机制如下:

FIFO信息的定义:

/*
该结构体定义成员有
缓存区,
长度,
输出,
输入的计数。
*/

typedef struct fifo_t {
    uint8_t *buf;
 uint32_t size;
 uint32_t in;
 uint32_t out;
} _fifo_str;
#define min(x,y) ((x) < (y)?(x):(y))  
1234567891011121314

1、初始化FIFO

fifo_str fifo_str;

int FifoInit(uint8_t *fifo_addr, uint32_t fifo_size)//初始化fifo
{
 _fifo_str *p = &fifo_str;
 
 if(fifo_addr == NULL || fifo_size == 0)//判断数据是否为空
  return -1;

 memset((char *)p, 0sizeof(_fifo_str));//初始化结构体
 p->buf = fifo_addr;//对应宽度
    p->in = 0;//输入计数
    p->out = 0;//输出计数
    p->size = fifo_size;//对应深度
 return 0;
}
12345678910111213141516

2、数据的长度获取

//数据的实际使用数据空间长度
int FifoDataLen(void)
{
 _fifo_str *p = &fifo_str;
 return (p->in - p->out);//输入计数-输出计数
}
//剩余数据空间长度
int FifoSpaceLen(void)
{
 _fifo_str *p = &fifo_str;
 
 return (p->size - (p->in - p->out));//定义长度-(实际长度)
}
12345678910111213

3、FIFO的进和出处理

//获取fifo数据
//数据的内容缓存区,要读的长度
int FifoRead(uint8_t *buf, uint32_t len)
{
 uint32_t i = 0, j = 0;
 _fifo_str *p = &fifo_str;

 j = (p->out % p->size);//获取剩余空间长度未读量
 len = min(len, p->in - p->out);//防止长度为超出实际拥有的数据长度,即让读取的长度在  (0<设定len<定义的缓存区长度len )这间的实际长度
 i = min(len, p->size - j);//获取实际内容的长度,的数据长度
 memcpy(buf, p->buf + j, i);//将数据通道里的数据拷贝给缓存区
 memcpy(buf + i, p->buf, len - i);//将未有数据的区域存入,对应为写入数据的区域数据(即,有数据的填数据,没数据的地方补0)
 p->out += len;//已读的数据量
 return len;//实际读到的数据长度
}
//对fifo写入数据
int FifoWrite(uint8_t *buf, uint32_t len)
{
 uint32_t i = 0, j = 0;
 _fifo_str *p = &fifo_str;

 j = p->in % p->size;//获取要写入的剩余空间长度
 len = min(len, p->size - p->in + p->out);//得到实际写入的长度
 i = min(len, p->size - j);//实际写入数据的长度
 memcpy(p->buf + j, buf, i);//将写入的数据的内容拷贝值数据中。
 memcpy(p->buf, buf + i, len - i);//补充多余空间的内容
 p->in += len;//记录实际写入数据的数量
 return len;//返回写入的长度
}

123456789101112131415161718192021222324252627282930

4、置位记录量

//清空fifo 中的记录量
void FifoClear(void)
{
 _fifo_str *p = &fifo_str;
    p->in = 0;
    p->out = 0;
}
1234567

5、应用处理机制

#define LEN 2048
uint8_t pdata[LEN] = {0};
FifoInit(pdata, LEN);//初始化FIFO
uint8_t buf[32] = {0}; 
int tx_len = 0;
uint8_t tx_buf[100] = {0};

HAL_UART_Receive_IT(&huart1, buf, IT_LEN);//串口的接收中断开启
while(1)
 { 
  tx_len = FifoDataLen();//获取数据长度
  if (tx_len > 0)
  {
   tx_len = (tx_len > 100) ? 100 : tx_len;//判读数据长度是否越界
   FifoRead(tx_buf, tx_len);//读取在中断中写入FIFO缓存的数据
   HAL_UART_Transmit(&huart1, tx_buf, tx_len, 1000);//将读到的数据通过串口发送出来
  }
 }

接收回调函数中的处理
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
 if (FifoSpaceLen() >= 串口记录的接收数据长度)//判断写入FIFO空间的数据量是否大于接收的数据量
 {
  FifoWrite(huart->pRxBuffPtr, huart->RxXferCount);//想FIFO中写入数据
 }

123456789101112131415161718192021222324252627

该FIFO的处理机制中用的记录是通过uint32t类型进行记录的,可能在遇到超出其数据极限的情况,导致数据通信异常。(该类型的数据极限较大,为特殊情况可能出现的情况)。

第二类、FIFO处理机制如下:

/* 定义串口波特率和FIFO缓冲区大小,
分为发送缓冲区和接收缓冲区*/
 
#if UART1_FIFO_EN == 1  
#define UART1_BAUD 115200  
#define UART1_TX_BUF_SIZE 1*1024  
#define UART1_RX_BUF_SIZE 1*1024
#endif 

/* 串口设备结构体
 设置发送、接收缓存区(长度),
 并设置两个变量,一个是指针,一个是计数
 */
 
typedef struct 
{
  
 USART_TypeDef *uart; /* STM32内部串口设备指针 */  

 uint8_t *pTxBuf; /* 发送缓冲区 */ 
  uint8_t *pRxBuf; /* 接收缓冲区 */ 
  uint16_t usTxBufSize; /* 发送缓冲区大小 */  
 uint16_t usRxBufSize; /* 接收缓冲区大小 */

   __IO uint16_t usTxWrite; /* 发送缓冲区写指针 */ 
  __IO uint16_t usTxRead; /* 发送缓冲区读指针 */  
  __IO uint16_t usTxCount; /* 等待发送的数据个数 */ 
 
   __IO uint16_t usRxWrite; /* 接收缓冲区写指针 */ 
   __IO uint16_t usRxRead; /* 接收缓冲区读指针 */
   __IO uint16_t usRxCount; /* 还未读取的新数据个数 */ 
  
 void (*SendBefor)(void); /* 开始发送之前的回调函数指针(主要用于RS485切换到发送模式) */  
 void (*SendOver)(void); /* 发送完毕的回调函数指针(主要用于RS485将发送模式切换为接收模式) */ 
 void (*ReciveNew)(uint8_t _byte); /* 串口收到数据的回调函数指针 */  
 uint8_t Sending; /* 正在发送中 */

 }UART_T;

/* 定义每个串口结构体变量 */ 
#if UART1_FIFO_EN == 1
static UART_T g_tUart1; 
static uint8_t g_TxBuf1[UART1_TX_BUF_SIZE]; /* 发送缓冲区 */  
static uint8_t g_RxBuf1[UART1_RX_BUF_SIZE]; /* 接收缓冲区 */ 
#endif

12345678910111213141516171819202122232425262728293031323334353637383940414243

怎样才叫做回调函数?回调函数,是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数, 当这个指针被用为调用它所指向的函数时, 我们就说这是回调函数。

区别指针函数和函数指针:

//指针函数:
int *fun(int x,int y)
int *x=fun(4,5);
在调用指针函数时,需要同类型的指针来接收函数返回值
是函数,返回值时指针
属于数据类型
123456
//函数指针:
int (*fun)(int x,int y)
int x(int x,int y);
x=fun;
fun=&x;
x=(*fun)(13);
是指针,指向函数。
属于函数名称
12345678

1.初始化串口FIFO对应的相关的变量

static void UartVarInit(void) 
{  
 #if UART1_FIFO_EN == 1 
  g_tUart1.uart = USART1; /* STM32 串口设备 */ 
  g_tUart1.pTxBuf = g_TxBuf1; /* 发送缓冲区指针 */ 
  g_tUart1.pRxBuf = g_RxBuf1; /* 接收缓冲区指针 */ 
  g_tUart1.usTxBufSize = UART1_TX_BUF_SIZE; /* 发送缓冲区大小 */ 
  g_tUart1.usRxBufSize = UART1_RX_BUF_SIZE; /* 接收缓冲区大小 */ 
  g_tUart1.usTxWrite = 0/* 发送FIFO写索引 */  
 g_tUart1.usTxRead = 0/* 发送FIFO读索引 */  
 g_tUart1.usRxWrite = 0/* 接收FIFO写索引 */  
 g_tUart1.usRxRead = 0/* 接收FIFO读索引 */  
 g_tUart1.usRxCount = 0/* 接收到的新数据个数 */  
 g_tUart1.usTxCount = 0/* 待发送的数据个数 */  
 g_tUart1.SendBefor = 0/* 发送数据前的回调函数 */  
 g_tUart1.SendOver = 0/* 发送完毕后的回调函数 */  
 g_tUart1.ReciveNew = 0/* 接收到新数据后的回调函数 */  
 g_tUart1.Sending = 0/* 正在发送中标志 */ 
 #endif 

1234567891011121314151617181920

明确中断服务程序的顺序:中断函数处理:void USART1_IRQHandler(void)—》 UART中断请求:HAL_UART_IRQHandler(UART_HandleTypeDef *huart)—》 中断使能:UART_Receive_IT— 》 中断回调函数 HAL_UART_RxCpltCallback(huart);

#if UART1_FIFO_EN == 1
void USART1_IRQHandler(void) //系统中串口的中断函数入口
{
    UartIRQ(&g_tUart1);
}
#endif

1234567

2.编辑自定义的UART中断请求

static void UartIRQ(UART_T *_pUart)
{
    uint32_t isrflags = READ_REG(_pUart->uart->ISR);
    uint32_t cr1its = READ_REG(_pUart->uart->CR1);
    uint32_t cr3its = READ_REG(_pUart->uart->CR3);

    if ((isrflags & USART_ISR_RXNE) != RESET)
    {
        /* 从串口接收数据寄存器读取数据存放到接收FIFO */
        uint8_t ch;
        ch = READ_REG(pUart->uart->RDR);
        /* 读串口接收数据寄存器 */
        _pUart->pRxBuf[_pUart->usRxWrite] = ch;         /* 填入串口接收FIFO */
        if (++_pUart->usRxWrite >= _pUart->usRxBufSize) /* 接收FIFO的写指针+1 */
        {
            _pUart->usRxWrite = 0;
        }
        if (_pUart->usRxCount < _pUart->usRxBufSize) /* 统计未处理的字节个数 */
        {
            _pUart->usRxCount++;
        }
        /* 回调函数,通知应用程序收到新数据,一般是发送1个消息或者设置一个标记 */
        // if (_pUart->usRxWrite == _pUart->usRxRead)
        // if (_pUart->usRxCount == 1)
        {
            if (_pUart->ReciveNew)
            {
                _pUart->ReciveNew(ch); /* 比如,交给MODBUS解码程序处理字节流 */
            }
        }
    }
    /* 处理发送缓冲区空中断 */
    if (((isrflags & USART_ISR_TXE) != RESET) && (cr1its & USART_CR1_TXEIE) != RESET)
    {
        // if (_pUart->usTxRead == _pUart->usTxWrite)
        if (_pUart->usTxCount == 0/* 发送缓冲区已无数据可取 */
        {
            /* 发送缓冲区的数据已取完时, 禁止发送缓冲区空中断 (注意:此时最后1个数据还未真正发送完毕)*/
            // USART_ITConfig(_pUart->uart, USART_IT_TXE, DISABLE);
            CLEAR_BIT(_pUart->uart->CR1, USART_CR1_TXEIE); /* 使能数据发送完毕中断 */
            // USART_ITConfig(_pUart->uart, USART_IT_TC, ENABLE);
            SET_BIT(_pUart->uart->CR1, USART_CR1_TCIE);
        }
        Else /* 还有数据等待发送 */
        {
            _pUart->Sending = 1/* 从发送FIFO取1个字节写入串口发送数据寄存器 */
            // USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
            _pUart->uart->TDR = _pUart->pTxBuf[_pUart->usTxRead];
            if (++_pUart->usTxRead >= _pUart->usTxBufSize)
            {
                _pUart->usTxRead = 0;
            }
            _pUart->usTxCount--;
        }
    }
    /* 数据bit位全部发送完毕的中断 */
    if (((isrflags & USART_ISR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
    {
        // if (_pUart->usTxRead == _pUart->usTxWrite)
        if (_pUart->usTxCount == 0)
        { /* 如果发送FIFO的数据全部发送完毕,禁止数据发送完毕中断 */
            // USART_ITConfig(_pUart->uart, USART_IT_TC, DISABLE);
            CLEAR_BIT(_pUart->uart->CR1, USART_CR1_TCIE); /* 回调函数, 一般用来处理RS485通信,将RS485芯片设置为接收模式,避免抢占总线 */
            if (_pUart->SendOver)
            {
                _pUart->SendOver();
            }
            _pUart->Sending = 0;
        }

        else
        { /* 正常情况下,不会进入此分支 */
            /* 如果发送FIFO的数据还未完毕,则从发送FIFO取1个数据写入发送数据寄存器 */
            // USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
            _pUart->uart->TDR = _pUart->pTxBuf[_pUart->usTxRead];
            if (++_pUart->usTxRead >= _pUart->usTxBufSize)
            {
                _pUart->usTxRead = 0;
            }
            _pUart->usTxCount--;
        }
    } /* 清除中断标志 */
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_PEF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_FEF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_NEF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_OREF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_IDLEF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_TCF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_LBDF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_CTSF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_CMF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_WUF);
    SET_BIT(_pUart->uart->ICR, UART_CLEAR_TXFECF);
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394

3.填写数据到UART发送缓冲区。

并启动发送中断,中断处理函数发送完毕后,自动关闭发送中断 .

static void UartSend(UART_T *_pUart, uint8_t *_ucaBuf, uint16_t _usLen) 
{  
 uint16_t i;  
  for (i = 0; i < _usLen; i++)  
 {  /* 如果发送缓冲区已经满了,则等待缓冲区空 */ 
   while (1)  
  {  
   __IO uint16_t usCount;   DISABLE_INT(); 
    usCount = _pUart->usTxCount; 
    ENABLE_INT();   
   if (usCount < _pUart->usTxBufSize)  
   {  
    break;  
   }  
   else if(usCount == _pUart->usTxBufSize)/* 数据已填满缓冲区 */  
   { 
     if((_pUart->uart->CR1 & USART_CR1_TXEIE) == 0
     {  
     SET_BIT(_pUart->uart->CR1, USART_CR1_TXEIE);  
    } 
    }  
  }   /* 将新数据填入发送缓冲区 */ 
   _pUart->pTxBuf[_pUart->usTxWrite] = _ucaBuf[i];  
   DISABLE_INT();  
  if (++_pUart->usTxWrite >= _pUart->usTxBufSize) 
   {  
   _pUart->usTxWrite = 0;  
  } 
   _pUart->usTxCount++;  
  ENABLE_INT(); 
  }  
  SET_BIT(_pUart->uart->CR1, USART_CR1_TXEIE); /* 使能发送中断(缓冲区空) */ 


12345678910111213141516171819202122232425262728293031323334

4.向串口发送一组数据。

数据放到发送缓冲区后立即返回,由中断服务程序在后台完成发送

void comSendBuf(COM_PORT_E _ucPort, uint8_t *_ucaBuf, uint16_t _usLen) 
{  
 UART_T *pUart;  
  pUart = ComToUart(_ucPort); 
  if (pUart == 0
  {
    return
  }  
  if (pUart->     != 0
  {
    pUart->SendBefor(); /* 如果是RS485通信,可以在这个函数中将RS485设置为发送模式 */  
 }  
  UartSend(pUart, _ucaBuf, _usLen); 
}

123456789101112131415

向串口发送1个字节。数据放到发送缓冲区后立即返回, 由中断服务程序在后台完成发送

void comSendChar(COM_PORT_E _ucPort, uint8_t _ucByte)
 
{  
 comSendBuf(_ucPort, &_ucByte, 1); 


123456

函数comSendChar是发送一个字节, 通过调用函数comSendBuf实现, 而函数comSendBuf又是通过调用函数UartSend实现, 这个函数是重点。

5.将COM端口号转换为UART指针

UART_T *ComToUart(COM_PORT_E _ucPort) 
{  
 if (_ucPort == COM1)  
 { 
  #if UART1_FIFO_EN == 1  
  return &g_tUart1; 
   #else 
   return 0;  
  #endif 
  }  
 else  
 {  
  Error_Handler(__FILE__, __LINE__);  
  return 0
  } 
}

1234567891011121314151617

6.从串口接收缓冲区读取1字节数据

static uint8_t UartGetChar(UART_T *_pUart, uint8_t *_pByte) 
{  

 uint16_t usCount;   /* usRxWrite 变量在中断函数中被改写,主程序读取该变量时,必须进行临界区保护 */  

 DISABLE_INT();  usCount = _pUart->usRxCount;  ENABLE_INT();   /* 如果读和写索引相同,则返回0 */ 
 
 //if (_pUart->usRxRead == usRxWrite)  
 if (usCount == 0/* 已经没有数据 */  
 {  
  return 0
  } 
  else  
 {  
  *_pByte = _pUart->pRxBuf[_pUart->usRxRead]; /* 从串口接收  FIFO取1个数据 */   
  /* 改写FIFO读索引 */  

  DISABLE_INT();
 
   if (++_pUart->usRxRead >= _pUart->usRxBufSize) 
   {  
   _pUart->usRxRead = 0;  
  }  
  _pUart->usRxCount--; 
   ENABLE_INT();  
  return 1;  
 }
 

1234567891011121314151617181920212223242526272829

从接收缓冲区读取1字节,非阻塞。无论有无数据均立即返回。

uint8_t comGetChar(COM_PORT_E _ucPort, uint8_t *_pByte) 
{

 UART_T *pUart;   
 pUart = ComToUart(_ucPort); 
  if (pUart == 0)
 {  
  return 0;  
 } 
   return UartGetChar(pUart, _pByte); 
}
123456789101112

接收数据的调用顺序是:comGetChar–》UartGetChar

7.判断发送缓冲区是否为空

uint8_t UartTxEmpty(COM_PORT_E _ucPort)
{
   UART_T *pUart;
   uint8_t Sending;
   
   pUart = ComToUart(_ucPort);
   if (pUart == 0)
   {
      return 0;
   }

   Sending = pUart->Sending;

   if (Sending != 0)
   {
      return 0;
   }
   return 1;
}

1234567891011121314151617181920

8.清零串口接收缓冲区

void comClearRxFifo(COM_PORT_E _ucPort)
{
 UART_T *pUart;
 pUart = ComToUart(_ucPort);
 if (pUart == 0)
 {
  return;
 }
 pUart->usRxWrite = 0;
 pUart->usRxRead = 0;
 pUart->usRxCount = 0;
}
123456789101112

9.清零串口发送缓冲区

void comClearTxFifo(COM_PORT_E _ucPort)
{
 UART_T *pUart;

 pUart = ComToUart(_ucPort);
 if (pUart == 0)
 {
  return;
 }

 pUart->usTxWrite = 0;
 pUart->usTxRead = 0;
 pUart->usTxCount = 0;
}
1234567891011121314

10.输入输出的重定向

int fputc(int ch, FILE *f)
{
#if 1 /* 将需要printf的字符通过串口中断FIFO发送出去,printf函数会立即返回 */
 comSendChar(COM1, ch);
 return ch;
#else /* 采用阻塞方式发送每个字符,等待数据发送完毕 */
 /* 写一个字节到USART1 */
 USART1->DR = ch;
 /* 等待发送结束 */
 while((USART1->SR & USART_SR_TC) == 0)
 {}
 return ch;
#endif
}


int fgetc(FILE *f)
{
#if 1 /* 从串口接收FIFO中取1个数据, 只有取到数据才返回 */
 uint8_t ucData;
 while(comGetChar(COM1, &ucData) == 0);
 return ucData;
#else
 /* 等待接收到数据 */
 while((USART1->SR & USART_SR_RXNE) == 0)
 {}
 return (int)USART1->DR;
#endif
}
1234567891011121314151617181920212223242526272829

11.应用层初始化:

//FIFO串口初始化
UartVarInit(void);
//串口参数配置
void bsp_SetUartParam(USART_TypeDef *Instance,  uint32_t BaudRate, uint32_t Parity, uint32_t Mode)
{
 UART_HandleTypeDef UartHandle; 
 /*##-1- 配置串口硬件参数 ######################################*/
 /* 异步串口模式 (UART Mode) */
 /* 配置如下:
   - 字长    = 8 位
   - 停止位  = 1 个停止位
   - 校验    = 参数Parity
   - 波特率  = 参数BaudRate
   - 硬件流控制关闭 (RTS and CTS signals) */

 UartHandle.Instance        = Instance;
 UartHandle.Init.BaudRate   = BaudRate;
 UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
 UartHandle.Init.StopBits   = UART_STOPBITS_1;
 UartHandle.Init.Parity     = Parity;
 UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
 UartHandle.Init.Mode       = Mode;
 UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
    
 if (HAL_UART_Init(&UartHandle) != HAL_OK)
 {
  Error_Handler(__FILE__, __LINE__);
 }
}
//对应的串口波特率配置
void comSetBaud(COM_PORT_E _ucPort, uint32_t _BaudRate)
{
 USART_TypeDef* USARTx;
 USARTx = ComToUSARTx(_ucPort);
 if (USARTx == 0)
 {
  return;
 }
 bsp_SetUartParam(USARTx,  _BaudRate, UART_PARITY_NONE, UART_MODE_TX_RX);
}
//硬件初始化
void InitHardUart(void)
{
GPIO 复用....
 /* 配置NVIC the NVIC for UART */   
 HAL_NVIC_SetPriority(USART1_IRQn, 01);
 HAL_NVIC_EnableIRQ(USART1_IRQn);
  
 /* 配置波特率、奇偶校验 */
 bsp_SetUartParam(USART1,  UART1_BAUD, UART_PARITY_NONE, UART_MODE_TX_RX);

 CLEAR_BIT(USART1->SR, USART_SR_TC);   /* 清除TC发送完成标志 */
    CLEAR_BIT(USART1->SR, USART_SR_RXNE); /* 清除RXNE接收标志 */
 // USART_CR1_PEIE | USART_CR1_RXNEIE
 SET_BIT(USART1->CR1, USART_CR1_RXNEIE); /* 使能PE. RX接受中断 */
}
在主循环中

comGetChar(COM1, &read);//获取一个字节数据
comSendBuf(COM1, (uint8_t *)buf, strlen(buf));//发送数据
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061


版权声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

关注我的微信公众号,回复“加群”按规则加入技术交流群。


点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

李肖遥 公众号“技术让梦想更伟大”,作者:李肖遥,专注嵌入式,只推荐适合你的博文,干货,技术心得,与君共勉。
评论 (0)
  •     在研究Corona现象时发现:临界电压与介电材料表面的清洁程度有关。表面越清洁的介电材料,临界电压越高;表面污染物越多的地方,越容易“爬电”。关于Corona现象,另见基础理论第007篇。    这里说的“污染物”,定义为——可能影响介电强度或表面电阻率的固体、液体或气体(电离气体)的任何情况。    IEC 60664-1 (对应GB/T 16935.1-2023) 定义了 Pollution Degree,中文术语是“污染等
    电子知识打边炉 2025-04-07 22:06 78浏览
  •   工业自动化领域电磁兼容与接地系统深度剖析   一、电磁兼容(EMC)基础认知   定义及关键意义   电磁兼容性(EMC),指的是设备或者系统在既定的电磁环境里,不但能按预期功能正常运转,而且不会对周边其他设备或系统造成难以承受的电磁干扰。在工业自动化不断发展的当下,大功率电机、变频器等设备被大量应用,现场总线、工业网络等技术也日益普及,致使工业自动化系统所处的电磁环境变得愈发复杂,电磁兼容(EMC)问题也越发严峻。   ​电磁兼容三大核心要素   屏蔽:屏蔽旨在切断电磁波的传播路
    北京华盛恒辉软件开发 2025-04-07 22:55 160浏览
  • 在人工智能技术飞速发展的今天,语音交互正以颠覆性的方式重塑我们的生活体验。WTK6900系列语音识别芯片凭借其离线高性能、抗噪远场识别、毫秒级响应的核心优势,为智能家居领域注入全新活力。以智能风扇为起点,我们开启一场“解放双手”的科技革命,让每一缕凉风都随“声”而至。一、核心技术:精准识别,无惧环境挑战自适应降噪,听懂你的每一句话WTK6900系列芯片搭载前沿信号处理技术,通过自适应降噪算法,可智能过滤环境噪声干扰。无论是家中电视声、户外虫鸣声,还是厨房烹饪的嘈杂声,芯片均能精准提取有效指令,识
    广州唯创电子 2025-04-08 08:40 134浏览
  • 在全球电子产业面临供应链波动、技术迭代和市场需求变化等多重挑战的背景下,安博电子始终秉持“让合作伙伴赢得更多一点”的核心理念,致力于打造稳健、高效、可持续的全球供应链体系。依托覆盖供应商管理、品质检测、智能交付的全链路品控体系,安博电子不仅能确保电子元器件的高可靠性与一致性,更以高透明的供应链管理模式,助力客户降低风险、提升运营效率,推动行业标准升级,与全球合作伙伴共同塑造更具前瞻性的产业生态。动态优选机制:构建纯净供应链生态安博电子将供应商管理视为供应链安全的根基。打造动态优选管控体系,以严格
    电子资讯报 2025-04-07 17:06 74浏览
  • HDMI从2.1版本开始采用FRL传输模式,和2.0及之前的版本不同。两者在物理层信号上有所区别,这就需要在一些2.1版本的电路设计上增加匹配电路,使得2.1版本的电路能够向下兼容2.0及之前版本。2.1版本的信号特性下面截取自2.1版本规范定义,可以看到2.1版本支持直流耦合和交流耦合,其共模电压和AVCC相关,信号摆幅在400mV-1200mV2.0及之前版本的信号特性HDMI2.0及之前版本采用TMDS信号物理层,其结构和参数如下:兼容设计根据以上规范定义,可以看出TMDS信号的共模电压范
    durid 2025-04-08 19:01 94浏览
  • 贞光科技作为三星电机车规电容代理商,针对电动汽车领域日益复杂的电容选型难题,提供全方位一站式解决方案。面对高温稳定性、高可靠性、高纹波电流和小型化等严苛要求,三星车规电容凭借完整产品矩阵和卓越技术优势,完美满足BMS、电机控制器和OBC等核心系统需求。无论技术选型、供应链保障、样品测试还是成本优化,贞光科技助力客户在电动汽车产业高速发展中占据技术先机。在电动汽车技术高速发展的今天,作为汽车电子系统中不可或缺的关键元器件,电容的选型已成为困扰许多工程师和采购人员的难题。如何在众多参数和型号中找到最
    贞光科技 2025-04-07 17:06 65浏览
  • 曾几何时,汽车之家可是汽车资讯平台领域响当当的“扛把子”。2005 年成立之初,它就像一位贴心的汽车小助手,一下子就抓住了大家的心。它不仅吸引了海量用户,更是成为汽车厂商和经销商眼中的“香饽饽”,广告投放、合作推广不断,营收和利润一路高歌猛进,2013年成功在纽交所上市,风光无限。2021年更是在香港二次上市,达到了发展的巅峰,当年3月15日上市首日,港股股价一度高达184.6港元,市值可观。然而,如今的汽车之家却陷入了困境,业务下滑明显。业务增长瓶颈从近年来汽车之家公布的财报数据来看,情况不容
    用户1742991715177 2025-04-07 21:48 86浏览
  • 在万物互联时代,智能化安防需求持续升级,传统报警系统已难以满足实时性、可靠性与安全性并重的要求。WT2003H-16S低功耗语音芯片方案,以4G实时音频传输、超低功耗设计、端云加密交互为核心,重新定义智能报警设备的性能边界,为家庭、工业、公共安防等领域提供高效、稳定的安全守护。一、技术内核:五大核心突破,构建全场景安防基座1. 双模音频传输,灵活应对复杂场景实时音频流传输:内置高灵敏度MIC,支持环境音实时采集,通过4G模块直接上传至云端服务器,响应速度低至毫秒级,适用于火灾警报、紧急呼救等需即
    广州唯创电子 2025-04-08 08:59 111浏览
  •     根据 IEC术语,瞬态过电压是指持续时间几个毫秒及以下的过高电压,通常是以高阻尼(快速衰减)形式出现,波形可以是振荡的,也可以是非振荡的。    瞬态过电压的成因和机理,IEC 60664-1给出了以下四种:    1. 自然放电,最典型的例子是雷击,感应到电力线路上,并通过电网配电系统传输,抵达用户端;        2. 电网中非特定感性负载通断。例如热处理工厂、机加工工厂对
    电子知识打边炉 2025-04-07 22:59 101浏览
  • 文/Leon编辑/cc孙聪颖‍转手绢、跳舞、骑车、后空翻,就在宇树、智元等独角兽企业率领“机器人大军”入侵短视频时,却有资本和科技大佬向此产业泼了一盆冷水。金沙江创投管理合伙人朱啸虎近日突然对人形机器人发难,他表示“最近几个月正在批量退出人形机器人公司”。“只是买回去做研究的,或者买回去做展示的,这种都不是我们意义上的商业化,谁会花十几万买一个机器人去干这些活?”朱啸虎吐槽。不过,朱啸虎的观点很快就遭到驳斥,众擎机器人的创始人、董事长赵同阳回怼道:“(朱啸虎)甚至问出了人形机器人在这个阶段有什么
    华尔街科技眼 2025-04-07 19:24 123浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦