对串口接收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  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

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


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

李肖遥 公众号“技术让梦想更伟大”,作者:李肖遥,专注嵌入式,只推荐适合你的博文,干货,技术心得,与君共勉。
评论
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 124浏览
  • 铁氧体芯片是一种基于铁氧体磁性材料制成的芯片,在通信、传感器、储能等领域有着广泛的应用。铁氧体磁性材料能够通过外加磁场调控其导电性质和反射性质,因此在信号处理和传感器技术方面有着独特的优势。以下是对半导体划片机在铁氧体划切领域应用的详细阐述: 一、半导体划片机的工作原理与特点半导体划片机是一种使用刀片或通过激光等方式高精度切割被加工物的装置,是半导体后道封测中晶圆切割和WLP切割环节的关键设备。它结合了水气电、空气静压高速主轴、精密机械传动、传感器及自动化控制等先进技术,具有高精度、高
    博捷芯划片机 2024-12-12 09:16 99浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 96浏览
  • 本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-ImportKeyPair工具在源码:build/target/product/security/系统初始签名文件目录中,将以下三个文件拷贝出来:platform.pem;platform.
    Industio_触觉智能 2024-12-12 10:27 93浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 123浏览
  • 应用环境与极具挑战性的测试需求在服务器制造领域里,系统整合测试(System Integration Test;SIT)是确保产品质量和性能的关键步骤。随着服务器系统的复杂性不断提升,包括:多种硬件组件、操作系统、虚拟化平台以及各种应用程序和服务的整合,服务器制造商面临着更有挑战性的测试需求。这些挑战主要体现在以下五个方面:1. 硬件和软件的高度整合:现代服务器通常包括多个处理器、内存模块、储存设备和网络接口。这些硬件组件必须与操作系统及应用软件无缝整合。SIT测试可以帮助制造商确保这些不同组件
    百佳泰测试实验室 2024-12-12 17:45 90浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-12 10:13 64浏览
  • 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进步,对于图像数据的采集、处理和分析的需求日益增长,这不仅要求我们拥有高性能的相机硬件,还要求我们能够高效地集成和测试各种算法。我们探索了一种多源相机数据采集与算法集成测试方案,能够满足不同应用场景下对图像采集和算法测试的多样化需求,确保数据的准确性和算法的有效性。一、相机组成相机一般由镜头(Lens),图像传感器(Image
    康谋 2024-12-12 09:45 104浏览
  • 天问Block和Mixly是两个不同的编程工具,分别在单片机开发和教育编程领域有各自的应用。以下是对它们的详细比较: 基本定义 天问Block:天问Block是一个基于区块链技术的数字身份验证和数据交换平台。它的目标是为用户提供一个安全、去中心化、可信任的数字身份验证和数据交换解决方案。 Mixly:Mixly是一款由北京师范大学教育学部创客教育实验室开发的图形化编程软件,旨在为初学者提供一个易于学习和使用的Arduino编程环境。 主要功能 天问Block:支持STC全系列8位单片机,32位
    丙丁先生 2024-12-11 13:15 73浏览
  • 全球智能电视时代来临这年头若是消费者想随意地从各个通路中选购电视时,不难发现目前市场上的产品都已是具有智能联网功能的智能电视了,可以宣告智能电视的普及时代已到临!Google从2021年开始大力推广Google TV(即原Android TV的升级版),其他各大品牌商也都跟进推出搭载Google TV操作系统的机种,除了Google TV外,LG、Samsung、Panasonic等大厂牌也开发出自家的智能电视平台,可以看出各家业者都一致地看好这块大饼。智能电视的Wi-Fi连线怎么消失了?智能电
    百佳泰测试实验室 2024-12-12 17:33 90浏览
  • 首先在gitee上打个广告:ad5d2f3b647444a88b6f7f9555fd681f.mp4 · 丙丁先生/香河英茂工作室中国 - Gitee.com丙丁先生 (mr-bingding) - Gitee.com2024年对我来说是充满挑战和机遇的一年。在这一年里,我不仅进行了多个开发板的测评,还尝试了多种不同的项目和技术。今天,我想分享一下这一年的故事,希望能给大家带来一些启发和乐趣。 年初的时候,我开始对各种开发板进行测评。从STM32WBA55CG到瑞萨、平头哥和平海的开发板,我都
    丙丁先生 2024-12-11 20:14 86浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-11 17:58 98浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦