搜索
bottom↓
回复: 57

请教51单片机串口收发缓存FIFO的写法

[复制链接]

出0入0汤圆

发表于 2021-2-2 03:21:46 | 显示全部楼层 |阅读模式
本帖最后由 mangolu 于 2021-2-2 03:24 编辑

这里的单片机用N76E003,我想要完成的功能就是从串口以115200波特率以100mS间隔发送一串数据到单片机,单片机原样返回。

看了很多资料就是开设两个缓存分别存储收发数据,在接收中断写接收缓存,然后在main函数循环里查询发送缓存,有数据则发送出去。并以一定时间间隔取接收缓存的数据写入发送缓存。

我以下的代码实现了这个功能,但是每隔一段时间会丢失一个数据。看似数据也没有丢失,后继会错会发回,就是少发回一个数,运行一段时间后,收发的数据相差越来越大:



丢失的数据,可以看到后续数据是会发回,但是整体少了个数据并错位:




想请教的是,这种收发方式应该怎么做?或者是不是我这里的缓存写得有问题?有人可能会说操作缓存要上锁,原子操作,我试过发现上锁,数据丢失更严重。

下面是代码:
  1. #include "stdint.h"
  2. #include "common.h"
  3. #include "Function_Define.h"
  4. #include "N76E003.h"
  5. #include "SFR_Macro.h"
  6. #include "fifo.h"



  7. FIFO xdata sRX_Buffer;        // 接收队列
  8. FIFO xdata sTX_Buffer;        // 发送队列
  9. uint8_t u8Busy_Flag = 0;        // 忙标志位

  10. uint8_t u8Temp;
  11. uint8_t u8Count = 0;

  12. void Uart_Send_Buffer(FIFO *sTX_Buffer);


  13. /** 需要自行定义部分结束<<< */


  14. void main(void) {
  15.         FSYS_Initial();        // 初始化时钟

  16.         Uart_Initial();        // 初始化串口

  17.         FIFO_Initial(&sRX_Buffer);        // 初如化接收队列
  18.         FIFO_Initial(&sTX_Buffer);        // 初如化发送队列

  19.         while(1) {
  20.                 u8Count ++;
  21.                 Uart_Send_Buffer(&sTX_Buffer);        // 串口发送发送队列

  22.                 if(u8Count > 10) {        // 16.6MHz时钟,大概10uS
  23.                         u8Count = 0;

  24.                         // if(FIFO_Out(&sRX_Buffer, &u8Temp) == FIFO_SUCESS) {        // 接收队列不为空
  25.                         if(FIFO_Get_Count(&sRX_Buffer) != 0) {        // 接收队列不为空
  26.                                 FIFO_Out(&sRX_Buffer, &u8Temp);
  27.                                 FIFO_In(&sTX_Buffer, u8Temp);        // 把接收队列的值写入发送队列中
  28.                         }

  29.                 }

  30.         }

  31. }

  32. /**
  33. * @brief  把队列数据从串口发送出去
  34. *
  35. * @param sTX_Buffer 要发送的队列缓存
  36. *
  37. * @par 函数说明:
  38. * 把队列数据从串口发送出去
  39. */
  40. void Uart_Send_Buffer(FIFO *sTX_Buffer) {
  41.         uint8_t u8Temp_Send;

  42.         if((u8Busy_Flag == 0) && (FIFO_Get_Count(sTX_Buffer) != 0)) {        // 忙标志位为不忙和发送队列不为空
  43.                 FIFO_Out(sTX_Buffer, &u8Temp_Send);
  44.                 SBUF_1 = u8Temp_Send;
  45.                 u8Busy_Flag = 1;        // 设置忙标志位为忙
  46.         }
  47. }

  48. /**
  49. * @brief  串口1中断处理
  50. *
  51. *
  52. * @par 函数说明:
  53. * 串口1中断处理,中断函数不需要声明。在其他应用中实现,要注释掉本函数。
  54. */
  55. void Uart1_ISR(void) interrupt 15 {        // 串口1中断向量为15
  56.         // uint8_t u8Temp1;

  57.         if (RI_1 == 1) {        // 接收中断
  58.                 clr_RI_1;        // 清接收中断,需手动清除

  59.                 /** 接收中断表示数据接收到,取串口缓存寄存器的值 */
  60.                 /** 存入FIFO中 */
  61.                 FIFO_In(&sRX_Buffer, SBUF_1);
  62.         }

  63.         if(TI_1 == 1) {        // 发送中断
  64.                 clr_TI_1;        // 清发送中断,需手动清除

  65.                 /** 发送中断表示数据发送完成,清忙标志 */
  66.                 u8Busy_Flag = 0;
  67.         }
  68. }

复制代码



fifo.c:
  1. #include "fifo.h"

  2. /**
  3. * @brief  初始化FIFO
  4. *
  5. * @param sFIFO 要初始化的FIFO
  6. * @return eFIFO_State 成功返回FIFO_SUCESS
  7. *
  8. * @par 函数说明:
  9. * 初始化FIFO:
  10. * 1. 数据头指向缓存0位置
  11. * 2. 数据尾指向缓存0位置
  12. * 3. 缓存区清零
  13. */
  14. eFIFO_State FIFO_Initial(FIFO *sFIFO) {
  15. #if(FIFO_SIZE < 256)    // 缓存小于256使用8位地址
  16.         uint8_t u8Count;

  17.         /** 初始化FIFO缓存区 */
  18.         for(u8Count = 0; u8Count < FIFO_SIZE; u8Count ++) {
  19.                 *(sFIFO->Buffer + u8Count) = 0;
  20.         }

  21. #elif(FIFO_SIZE >= 256)    // 缓存大于等于256使用16位地址
  22.         uint16_t u16Count;

  23.         /** 初始化FIFO缓存区 */
  24.         for(u16Count = 0; u16Count < FIFO_SIZE; u16Count ++) {
  25.                 *(sFIFO->Buffer + u16Count) = 0;
  26.         }

  27. #endif  /** FIFO_SIZE */

  28.         sFIFO->Count = 0;   // 存储数据字节数初始化
  29.         sFIFO->Front = 0;   // 数据头位置初始化
  30.         sFIFO->Rear = 0;    // 数据尾位置初始化

  31.         return FIFO_SUCESS;
  32. }

  33. /**
  34. * @brief  存储一个数据到FIFO中
  35. *
  36. * @param sFIFO 要操作的FIFO
  37. * @param u8Data 要存储的数据
  38. * @return eFIFO_State :
  39. * 1. 成功返回 FIFO_SUCESS FIFO操作成功
  40. * 2. FIFO已满,无法写入返回 FIFO_FULL FIFO已满
  41. *
  42. * @par 函数说明:
  43. * 存储一个数据到FIFO中。
  44. */
  45. eFIFO_State FIFO_In(FIFO *sFIFO, uint8_t u8Data) reentrant {
  46.         eFIFO_State eState = FIFO_SUCESS;  // 初始状态值为FIFO_SUCESS

  47.         if(sFIFO->Count == FIFO_SIZE) {  // FIFO已满
  48.                 eState = FIFO_FULL;    // 设置状态值为FIFO_FULL
  49.         } else {
  50.                 /** 循环写入,写满返回位置0写 */
  51.                 *(sFIFO->Buffer + sFIFO->Rear) = u8Data;   // 数据存入缓存尾部
  52.                 sFIFO->Rear = (sFIFO->Rear + 1) % FIFO_SIZE;  // 数据尾与缓存长度取模,使数据尾永远在缓存长度范围内
  53.                 (sFIFO->Count) ++;    // 存储数据字节数加1
  54.         }

  55.         return eState;
  56. }

  57. /**
  58. * @brief  从FIFO中读出数据,并存入指定指针中
  59. *
  60. * @param sFIFO 要操作的FIFO
  61. * @param u8pData 存储读出数据的指针
  62. * @return eFIFO_State :
  63. * 1. 成功返回 FIFO_SUCESS FIFO操作成功
  64. * 2. FIFO已空,无法读出返回 FIFO_EMPTY FIFO已空
  65. *
  66. * @par 函数说明:
  67. * 从FIFO中读出数据,并存入指定指针中。
  68. */
  69. eFIFO_State FIFO_Out(FIFO *sFIFO, uint8_t *u8pData) reentrant {
  70.         eFIFO_State eState = FIFO_SUCESS;  // 初始状态值为FIFO_SUCESS

  71.         if(sFIFO->Count == 0) {  // FIFO已空
  72.                 eState = FIFO_EMPTY;   // 设置状态值为FIFO_EMPTY
  73.         } else {
  74.                 /** 循环读取,写满返回位置0读 */
  75.                 *u8pData = *(sFIFO->Buffer + sFIFO->Front); // 从缓存中读取数据
  76.                 sFIFO->Front = (sFIFO->Front + 1) % FIFO_SIZE;  // 数据头与缓存长度取模,使数据头永远在缓存长度范围内
  77.                 (sFIFO->Count) --;    // 存储数据字节数减1
  78.         }

  79.         return eState;
  80. }

  81. /**
  82. * @brief  获取FIFO中存储数据字节数
  83. *
  84. * @param sFIFO 要操作的FIFO
  85. * @return uint16_t FIFO中存储数据字节数
  86. *
  87. * @par 函数说明:
  88. * 存储数据字节数
  89. */
  90. uint16_t FIFO_Get_Count(FIFO *sFIFO) {

  91.         return (sFIFO->Count);
  92. }
复制代码



fifo.h:

#ifndef _FIFO_H_
#define _FIFO_H_

#include "stdint.h"
#include "common.h"

#define FIFO_SIZE   32  /** 定义FIFO缓存长度 */


/**
* @brief  FIFO状态定义枚举
*
* @par 函数说明:
* FIFO状态定义枚举
*/
typedef enum {
        FIFO_SUCESS,    // FIFO操作成功
        FIFO_FULL,      // FIFO已满
        FIFO_EMPTY,     // FIFO已空
    FIFO_LOCK,      // FIFO已上锁
} eFIFO_State;

/**
* @brief  FIFO结构定义
*
* @par 函数说明:
* FIFO结构定义。从数据头读出,从数据尾写入。
*/
#if(FIFO_SIZE < 256)    // 缓存小于256使用8位地址
typedef struct {
        uint8_t Count;      // 存储数据字节数
        uint8_t Front;      // 数据头位置,指向数据读出的位置
        uint8_t Rear;       // 数据尾位置,指向数据写入的位置
        uint8_t Buffer[FIFO_SIZE];  // 数据存储缓存
} FIFO;
#elif(FIFO_SIZE >= 256)    // 缓存大于等于256使用16位地址
typedef struct {
        uint16_t Count; // 存储数据字节数
        uint16_t Front; // 数据头位置,指向数据读出的位置
        uint16_t Rear;  // 数据尾位置,指向数据写入的位置
        uint8_t Buffer[FIFO_SIZE];  // 数据存储缓存
} FIFO;
#endif  /** FIFO_SIZE */

/**
* @brief  初始化FIFO
*
* @param sFIFO 要初始化的FIFO
* @return eFIFO_State 成功返回FIFO_SUCESS
*
* @par 函数说明:
* 初始化FIFO:
* 1. 数据头指向缓存0位置
* 2. 数据尾指向缓存0位置
* 3. 缓存区清零
*/
eFIFO_State FIFO_Initial(FIFO *sFIFO);

/**
* @brief  存储一个数据到FIFO中
*
* @param sFIFO 要操作的FIFO
* @param u8Data 要存储的数据
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已满,无法写入返回 FIFO_FULL FIFO已满
*
* @par 函数说明:
* 存储一个数据到FIFO中。
*/
eFIFO_State FIFO_In(FIFO *sFIFO, uint8_t u8Data) reentrant;

/**
* @brief  从FIFO中读出数据,并存入指定指针中
*
* @param sFIFO 要操作的FIFO
* @param u8pData 存储读出数据的指针
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已空,无法读出返回 FIFO_EMPTY FIFO已空
*
* @par 函数说明:
* 从FIFO中读出数据,并存入指定指针中。
*/
eFIFO_State FIFO_Out(FIFO *sFIFO, uint8_t *u8pData) reentrant;

/**
* @brief  获取FIFO中存储数据字节数
*
* @param sFIFO 要操作的FIFO
* @return uint16_t FIFO中存储数据字节数
*
* @par 函数说明:
* 存储数据字节数
*/
uint16_t FIFO_Get_Count(FIFO *sFIFO);

#endif        /** _FIFO_H_ */

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

发表于 2021-2-2 08:04:16 | 显示全部楼层
1,在前后台中,不要运行同一个函数。
2,在51MCU使用指针,最好是使用基于存储器的指针。

出0入0汤圆

 楼主| 发表于 2021-2-2 08:27:24 来自手机 | 显示全部楼层
su33691 发表于 2021-2-2 08:04
1,在前后台中,不要运行同一个函数。
2,在51MCU使用指针,最好是使用基于存储器的指针。 ...

这里把fifo写成可重入函数,难道要把函数打散,分别写对各个缓存的操作?
不懂什么叫基于存储器指针?大神能否指点下我这里指针有什么问题吗?

出0入0汤圆

发表于 2021-2-2 08:34:44 | 显示全部楼层
本帖最后由 su33691 于 2021-2-2 08:36 编辑

//fifo.c:
#include "fifo.h"


/**
* @brief  初始化FIFO
*
* @param sFIFO 要初始化的FIFO
* @return eFIFO_State 成功返回FIFO_SUCESS
*
* @par 函数说明:
* 初始化FIFO:
* 1. 数据头指向缓存0位置
* 2. 数据尾指向缓存0位置
* 3. 缓存区清零
*/
eFIFO_State FIFO_Initial(FIFO xdata *sFIFO) {
#if(FIFO_SIZE < 256)    // 缓存小于256使用8位地址
        uint8_t u8Count;

        /** 初始化FIFO缓存区 */
        for(u8Count = 0; u8Count < FIFO_SIZE; u8Count ++) {
                *(sFIFO->Buffer + u8Count) = 0;
        }

#elif(FIFO_SIZE >= 256)    // 缓存大于等于256使用16位地址
        uint16_t u16Count;

        /** 初始化FIFO缓存区 */
        for(u16Count = 0; u16Count < FIFO_SIZE; u16Count ++) {
                *(sFIFO->Buffer + u16Count) = 0;
        }

#endif  /** FIFO_SIZE */

        sFIFO->Count = 0;   // 存储数据字节数初始化
        sFIFO->Front = 0;   // 数据头位置初始化
        sFIFO->Rear = 0;    // 数据尾位置初始化

        return FIFO_SUCESS;
}

/**
* @brief  存储一个数据到FIFO中
*
* @param sFIFO 要操作的FIFO
* @param u8Data 要存储的数据
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已满,无法写入返回 FIFO_FULL FIFO已满
*
* @par 函数说明:
* 存储一个数据到FIFO中。

eFIFO_State FIFO_In(FIFO xdata *sFIFO, uint8_t u8Data) reentrant {
        eFIFO_State eState = FIFO_SUCESS;  // 初始状态值为FIFO_SUCESS

        if(sFIFO->Count == FIFO_SIZE) {  // FIFO已满
                eState = FIFO_FULL;    // 设置状态值为FIFO_FULL
        } else {
                // 循环写入,写满返回位置0写
                *(sFIFO->Buffer + sFIFO->Rear) = u8Data;   // 数据存入缓存尾部
                sFIFO->Rear = (sFIFO->Rear + 1) % FIFO_SIZE;  // 数据尾与缓存长度取模,使数据尾永远在缓存长度范围内
                (sFIFO->Count) ++;    // 存储数据字节数加1
        }

        return eState;
}
*/

void FIFO_In_RXBuff(FIFO xdata *sFIFO, uint8_t u8Data)
{
        if(sFIFO->Count != FIFO_SIZE)         // FIFO不满
        {  
                *(sFIFO->Buffer + sFIFO->Rear) = u8Data;   // 数据存入缓存尾部
                sFIFO->Rear = (sFIFO->Rear + 1) % FIFO_SIZE;  // 数据尾与缓存长度取模,使数据尾永远在缓存长度范围内
                (sFIFO->Count) ++;    // 存储数据字节数加1
        }
}


void FIFO_In_TXBuff(FIFO xdata *sFIFO, uint8_t u8Data)
{
        if(sFIFO->Count != FIFO_SIZE)         // FIFO不满
        {  
                *(sFIFO->Buffer + sFIFO->Rear) = u8Data;   // 数据存入缓存尾部
                sFIFO->Rear = (sFIFO->Rear + 1) % FIFO_SIZE;  // 数据尾与缓存长度取模,使数据尾永远在缓存长度范围内
                (sFIFO->Count) ++;    // 存储数据字节数加1
        }
}


/**
* @brief  从FIFO中读出数据,并存入指定指针中
*
* @param sFIFO 要操作的FIFO
* @param u8pData 存储读出数据的指针
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已空,无法读出返回 FIFO_EMPTY FIFO已空
*
* @par 函数说明:
* 从FIFO中读出数据,并存入指定指针中。
*/
eFIFO_State FIFO_Out(FIFO xdata *sFIFO, uint8_t data *u8pData) //reentrant
{
        eFIFO_State eState = FIFO_SUCESS;  // 初始状态值为FIFO_SUCESS

        if(sFIFO->Count == 0) {  // FIFO已空
                eState = FIFO_EMPTY;   // 设置状态值为FIFO_EMPTY
        } else {
                /** 循环读取,写满返回位置0读 */
                *u8pData = *(sFIFO->Buffer + sFIFO->Front); // 从缓存中读取数据
                sFIFO->Front = (sFIFO->Front + 1) % FIFO_SIZE;  // 数据头与缓存长度取模,使数据头永远在缓存长度范围内
                (sFIFO->Count) --;    // 存储数据字节数减1
        }

        return eState;
}

/**
* @brief  获取FIFO中存储数据字节数
*
* @param sFIFO 要操作的FIFO
* @return uint16_t FIFO中存储数据字节数
*
* @par 函数说明:
* 存储数据字节数
*/
uint16_t FIFO_Get_Count(FIFO xdata *sFIFO) {

        return (sFIFO->Count);
}

出0入0汤圆

发表于 2021-2-2 08:41:52 | 显示全部楼层
if(sFIFO->Count != FIFO_SIZE)         // FIFO不满

改为:
if(sFIFO->Count < FIFO_SIZE)         // FIFO不满

出0入0汤圆

 楼主| 发表于 2021-2-2 08:42:12 来自手机 | 显示全部楼层
su33691 发表于 2021-2-2 08:34
//fifo.c:
#include "fifo.h"


谢谢,晚点我改下试试。

出0入16汤圆

发表于 2021-2-2 08:43:17 | 显示全部楼层
有帧头这种协议框架的不容易丢失,直接收发对可靠性要求太高,单片机如何保证一帧数据接受完成,同时要保证在发送的时候没有数据接受进来,你这种接受完成只能基于中断超时

出0入0汤圆

 楼主| 发表于 2021-2-2 08:49:35 来自手机 | 显示全部楼层
初音之恋 发表于 2021-2-2 08:43
有帧头这种协议框架的不容易丢失,直接收发对可靠性要求太高,单片机如何保证一帧数据接受完成,同时要保证 ...

这里数据持续收发,本来是想试一下串口的稳定性,我就是想试一下这种情况不丢失数据怎么处理。

出0入4汤圆

发表于 2021-2-2 08:56:37 来自手机 | 显示全部楼层
接收中断超时就很好做呀,这样处理又简单,逻辑一看就明白。你想测试串口稳定性就应该用最简单的代码。
   

出0入0汤圆

 楼主| 发表于 2021-2-2 09:10:01 来自手机 | 显示全部楼层
Landmark 发表于 2021-2-2 08:56
接收中断超时就很好做呀,这样处理又简单,逻辑一看就明白。你想测试串口稳定性就应该用最简单的代码。
    ...

假设我持续发送,并没有间隔,也没有帧头帧尾怎么处理?坛里这几天有个帖子stc8g的,就是这样的情况。我不懂那个示例代码在stc8上运行如何,我手里没有这个stc8的板子。我看示例代码就是我楼主位的处理方法,我这里也是根据自己理解写的程序。

出0入0汤圆

 楼主| 发表于 2021-2-2 10:33:10 | 显示全部楼层
su33691 发表于 2021-2-2 08:41
if(sFIFO->Count != FIFO_SIZE)         // FIFO不满

改为:

已经改为你上面的了,还是一样子会丢失一个数据。

出0入442汤圆

发表于 2021-2-2 10:36:32 来自手机 | 显示全部楼层
mangolu 发表于 2021-2-2 08:27
这里把fifo写成可重入函数,难道要把函数打散,分别写对各个缓存的操作?
不懂什么叫基于存储器指针?大 ...

你要做两个fifo,1t1r。r在中断里填入,t当tx空闲时由程序直接写硬件,否则在tx中断里写硬件。

此外你要留点延迟,你这种丢数据可能是两侧时钟偏差较大造成的。

出0入0汤圆

 楼主| 发表于 2021-2-2 11:04:52 来自手机 | 显示全部楼层
wye11083 发表于 2021-2-2 10:36
你要做两个fifo,1t1r。r在中断里填入,t当tx空闲时由程序直接写硬件,否则在tx中断里写硬件。

此外你要 ...

上面已经改为每个缓存一个写函数,读的话就读发送缓存就没改,结果是一样的

出0入442汤圆

发表于 2021-2-2 11:09:36 来自手机 | 显示全部楼层
mangolu 发表于 2021-2-2 11:04
上面已经改为每个缓存一个写函数,读的话就读发送缓存就没改,结果是一样的 ...

干吗要用count?要想兼容中断和非中断且保证可靠性,只能使用rw ptr。如果(w+1)=r,则写满。如果r=w,则读空。

出0入0汤圆

 楼主| 发表于 2021-2-2 11:15:29 来自手机 | 显示全部楼层
wye11083 发表于 2021-2-2 11:09
干吗要用count?要想兼容中断和非中断且保证可靠性,只能使用rw ptr。如果(w+1)=r,则写满。如果r=w, ...

谢谢,我想一下

出0入8汤圆

发表于 2021-2-2 11:21:38 | 显示全部楼层
mangolu 发表于 2021-2-2 09:10
假设我持续发送,并没有间隔,也没有帧头帧尾怎么处理?坛里这几天有个帖子stc8g的,就是这样的情况。我 ...

仅仅测试串口的稳定性,就是用 9 楼的方法,反而你这边引入的问题,不是串口的问题了。

出0入0汤圆

 楼主| 发表于 2021-2-2 11:47:17 来自手机 | 显示全部楼层
security 发表于 2021-2-2 11:21
仅仅测试串口的稳定性,就是用 9 楼的方法,反而你这边引入的问题,不是串口的问题了。 ...

本来是想测试串口,后面发现使用队列出现这个问题,现在是想怎么解决这个:)

出0入8汤圆

发表于 2021-2-2 11:50:14 | 显示全部楼层
mangolu 发表于 2021-2-2 11:47
本来是想测试串口,后面发现使用队列出现这个问题,现在是想怎么解决这个:) ...


14 楼的,读、写双指针。
给个参考实现:RT-Thread 里面的 ringbuffer.c(rt-thread\components\drivers\src\ringbuffer.c)。

出0入0汤圆

 楼主| 发表于 2021-2-2 12:23:27 来自手机 | 显示全部楼层
wye11083 发表于 2021-2-2 11:09
干吗要用count?要想兼容中断和非中断且保证可靠性,只能使用rw ptr。如果(w+1)=r,则写满。如果r=w, ...

初始:r = w = 0
读写各一个:r=1 w=1,此时不能说明为空吧?

w + 1 = r,也只有r =0才会出现?

或许是我理解有误或算法不对。请教能否提供一下你队列实现的方法?

出0入0汤圆

 楼主| 发表于 2021-2-2 12:24:16 来自手机 | 显示全部楼层
security 发表于 2021-2-2 11:50
14 楼的,读、写双指针。
给个参考实现:RT-Thread 里面的 ringbuffer.c(rt-thread\components\drivers\ ...

谢谢,没用过rtt,有空再看看

出0入0汤圆

发表于 2021-2-2 14:05:57 | 显示全部楼层
Landmark 发表于 2021-2-2 08:56
接收中断超时就很好做呀,这样处理又简单,逻辑一看就明白。你想测试串口稳定性就应该用最简单的代码。
    ...

这种处理完全没问题

出0入0汤圆

发表于 2021-2-2 14:23:33 | 显示全部楼层
mangolu 发表于 2021-2-2 10:33
已经改为你上面的了,还是一样子会丢失一个数据。

我用上述代码在STC8H1K08测试,22.1184MHZ频率,115200BSP。串口OK,不会丢数据。

出0入0汤圆

发表于 2021-2-2 14:34:19 | 显示全部楼层
全部代码:

//main.c
//115200bps@22.1184MHz

#include "fifo.h"


FIFO xdata sRX_Buffer = {0,0,0,{0}};        // 接收队列
FIFO xdata sTX_Buffer = {0,0,0,{0}};        // 发送队列
uint8_t u8Busy_Flag = 0;        // 忙标志位

uint8_t u8Temp;
uint8_t u8Count = 0;

void Uart_Send_Buffer(FIFO xdata *sTX_Buffer);


void Uart_Initial(void)                //115200bps@22.1184MHz
{
        P_SW1 = 0x40;                //P36,P37
       
        SCON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //设定定时器1为16位自动重装方式
        TL1 = 0xD0;                //设定定时初值
        TH1 = 0xFF;                //设定定时初值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        ES = 1;                        //使能串口中断
}

void InitGpio(void)        //IO初始化
{
//        P1 = 0xfe;       
       
        P1M0 = 0x00;        //P1.0配置为推挽输出
        P1M1 = 0x00;       
       
        P3M0 = 0x80;        //P37配置为推挽输出
        P3M1 = 0x00;
       
        P5M0 = 0x00;        //
        P5M1 = 0x00;
}



/** 需要自行定义部分结束<<< */


void main(void)
{
        InitGpio();        // 初始化IO

        Uart_Initial();        // 初始化串口

//        FIFO_Initial(&sRX_Buffer);        // 初如化接收队列
//        FIFO_Initial(&sTX_Buffer);        // 初如化发送队列
       
        EA = 1;
        while(1)
        {
                u8Count ++;
                Uart_Send_Buffer(&sTX_Buffer);        // 串口发送发送队列

                if(u8Count > 10)
                {        // 16.6MHz时钟,大概10uS
                        u8Count = 0;
                       
                        if(FIFO_Get_Count(&sRX_Buffer) != 0)
                        {        // 接收队列不为空
                                FIFO_Out(&sRX_Buffer, &u8Temp);
                                FIFO_In_TXBuff(&sTX_Buffer, u8Temp); // 把接收队列的值写入发送队列中
                        }
                }
        }
}

/**
* @brief  把队列数据从串口发送出去
*
* @param sTX_Buffer 要发送的队列缓存
*
* @par 函数说明:
* 把队列数据从串口发送出去
*/
void Uart_Send_Buffer(FIFO xdata *sTX_Buffer)
{
        uint8_t u8Temp_Send;

        if((u8Busy_Flag == 0) && (FIFO_Get_Count(sTX_Buffer) != 0))
        {        // 忙标志位为不忙和发送队列不为空
                FIFO_Out(sTX_Buffer, &u8Temp_Send);
                SBUF = u8Temp_Send;
                u8Busy_Flag = 1;        // 设置忙标志位为忙
        }
}

/**
* @brief  串口1中断处理
*
*
* @par 函数说明:
* 串口1中断处理,中断函数不需要声明。在其他应用中实现,要注释掉本函数。
*/
void Uart1_ISR(void) interrupt 4
{        // 串口1中断向量为15
        // uint8_t u8Temp1;

        if (RI)
        {        // 接收中断
                RI = 0;        // 清接收中断,需手动清除

                /** 接收中断表示数据接收到,取串口缓存寄存器的值 */
                /** 存入FIFO中 */
                FIFO_In_RXBuff(&sRX_Buffer, SBUF);
        }

        if(TI)
        {        // 发送中断
                TI = 0;        // 清发送中断,需手动清除

                /** 发送中断表示数据发送完成,清忙标志 */
                u8Busy_Flag = 0;
        }
}


//fifo.c:
#include "fifo.h"


/**
* @brief  存储一个数据到FIFO中
*
* @param sFIFO 要操作的FIFO
* @param u8Data 要存储的数据
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已满,无法写入返回 FIFO_FULL FIFO已满
*
* @par 函数说明:
* 存储一个数据到FIFO中。
*/

void FIFO_In_RXBuff(FIFO xdata *sFIFO, uint8_t u8Data)
{
        if(sFIFO->Count < FIFO_SIZE)         // FIFO不满
        {  
                *(sFIFO->Buffer + sFIFO->Rear) = u8Data;   // 数据存入缓存尾部
                sFIFO->Rear = (sFIFO->Rear + 1) % FIFO_SIZE;  // 数据尾与缓存长度取模,使数据尾永远在缓存长度范围内
                (sFIFO->Count) ++;    // 存储数据字节数加1
        }
}


void FIFO_In_TXBuff(FIFO xdata *sFIFO, uint8_t u8Data)
{
        if(sFIFO->Count < FIFO_SIZE)         // FIFO不满
        {  
                *(sFIFO->Buffer + sFIFO->Rear) = u8Data;   // 数据存入缓存尾部
                sFIFO->Rear = (sFIFO->Rear + 1) % FIFO_SIZE;  // 数据尾与缓存长度取模,使数据尾永远在缓存长度范围内
                (sFIFO->Count) ++;    // 存储数据字节数加1
        }
}


/**
* @brief  从FIFO中读出数据,并存入指定指针中
*
* @param sFIFO 要操作的FIFO
* @param u8pData 存储读出数据的指针
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已空,无法读出返回 FIFO_EMPTY FIFO已空
*
* @par 函数说明:
* 从FIFO中读出数据,并存入指定指针中。
*/
void FIFO_Out(FIFO xdata *sFIFO, uint8_t data *u8pData) //reentrant
{
//        eFIFO_State eState = FIFO_SUCESS;  // 初始状态值为FIFO_SUCESS

        if(sFIFO->Count != 0)
        {
                /** 循环读取,写满返回位置0读 */
                *u8pData = *(sFIFO->Buffer + sFIFO->Front); // 从缓存中读取数据
                sFIFO->Front = (sFIFO->Front + 1) % FIFO_SIZE;  // 数据头与缓存长度取模,使数据头永远在缓存长度范围内
        //        (sFIFO->Count) --;    // 存储数据字节数减1
                (sFIFO->Count) --;
        }

//        return eState;
}

/**
* @brief  获取FIFO中存储数据字节数
*
* @param sFIFO 要操作的FIFO
* @return uint16_t FIFO中存储数据字节数
*
* @par 函数说明:
* 存储数据字节数
*/
uint8_t FIFO_Get_Count(FIFO xdata *sFIFO)
{
        return (sFIFO->Count);
}


//fifo.h:

#ifndef _FIFO_H_
#define _FIFO_H_


#include "STC8H.h"

#define FIFO_SIZE   32  /** 定义FIFO缓存长度 */


/**
* @brief  FIFO状态定义枚举
*
* @par 函数说明:
* FIFO状态定义枚举
*/
typedef enum {
        FIFO_SUCESS,    // FIFO操作成功
        FIFO_FULL,      // FIFO已满
        FIFO_EMPTY,     // FIFO已空
    FIFO_LOCK,      // FIFO已上锁
} eFIFO_State;

/**
* @brief  FIFO结构定义
*
* @par 函数说明:
* FIFO结构定义。从数据头读出,从数据尾写入。
*/

typedef struct
{
        uint8_t Count;      // 存储数据字节数
        uint8_t Front;      // 数据头位置,指向数据读出的位置
        uint8_t Rear;       // 数据尾位置,指向数据写入的位置
        uint8_t Buffer[FIFO_SIZE];  // 数据存储缓存
} FIFO;




/**
* @brief  存储一个数据到FIFO中
*
* @param sFIFO 要操作的FIFO
* @param u8Data 要存储的数据
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已满,无法写入返回 FIFO_FULL FIFO已满
*
* @par 函数说明:
* 存储一个数据到FIFO中。
*/
//eFIFO_State FIFO_In(FIFO xdata *sFIFO, uint8_t u8Data) reentrant;
void FIFO_In_RXBuff(FIFO xdata *sFIFO, uint8_t u8Data);
void FIFO_In_TXBuff(FIFO xdata *sFIFO, uint8_t u8Data);

/**
* @brief  从FIFO中读出数据,并存入指定指针中
*
* @param sFIFO 要操作的FIFO
* @param u8pData 存储读出数据的指针
* @return eFIFO_State :
* 1. 成功返回 FIFO_SUCESS FIFO操作成功
* 2. FIFO已空,无法读出返回 FIFO_EMPTY FIFO已空
*
* @par 函数说明:
* 从FIFO中读出数据,并存入指定指针中。
*/
void FIFO_Out(FIFO xdata *sFIFO, uint8_t data *u8pData);

/**
* @brief  获取FIFO中存储数据字节数
*
* @param sFIFO 要操作的FIFO
* @return uint16_t FIFO中存储数据字节数
*
* @par 函数说明:
* 存储数据字节数
*/
uint8_t FIFO_Get_Count(FIFO xdata *sFIFO);

#endif        /** _FIFO_H_ */

出0入0汤圆

 楼主| 发表于 2021-2-2 14:57:40 来自手机 | 显示全部楼层
su33691 发表于 2021-2-2 14:34
全部代码:

//main.c

那就很奇怪。你这个是外置晶振吗?n76e003是内置RC,会不会跟这个有关?

出0入50汤圆

发表于 2021-2-2 15:50:41 | 显示全部楼层
自定义协议一般会定义帧头或者帧尾,否则无法判别是否一帧有效数据,也没法进行处理,接收的时候,只管往buf里填充,同时不断增加指针地址,每次接收字节做一个简单判断是不是帧头或帧尾就可以。
标准协议,比如MODBUS-RTU,可以用标准的3.5T超时处理。
曾经测试过一个51产品,115200bps,疯狂做MODBUS-RTU的测试,100万次通信没有发现错误,后来实在忍不住关掉了测试。

出0入8汤圆

发表于 2021-2-2 15:58:35 | 显示全部楼层
本帖最后由 security 于 2021-2-2 15:59 编辑
mangolu 发表于 2021-2-2 14:57
那就很奇怪。你这个是外置晶振吗?n76e003是内置RC,会不会跟这个有关?


都会的,只不过,刚好避开了踩坑的时间点。

main 中的 FIFO_Out(&sRX_Buffer, &u8Temp);,对 count 递减
ISR 中 FIFO_In_RXBuff(&sRX_Buffer, SBUF);,对 count 递增,
对 count 的操作,并不是原子操作,时间久了,踩到点了,就会使得 count 错乱掉。

例如,main 中的对 count 的递减操作:
  1. MOVX     A,@DPTR
  2. DEC     A
  3. MOVX     @DPTR,A
复制代码

如果在 DEC A 之前(假设此时 count = 8,那么 A = 8),发生了接收中断,进入到 ISR,那么 count 数,将自增为 9,
然后继续返回到 main 中,继续执行 :
  1. DEC     A
  2. MOVX     @DPTR,A
复制代码
。此时 A = 8,那么 count 的数值,将被修改为 7,这里就出现了问题了。

出0入0汤圆

 楼主| 发表于 2021-2-2 16:05:48 来自手机 | 显示全部楼层
security 发表于 2021-2-2 15:58
都会的,只不过,刚好避开了踩坑的时间点。

main 中的 FIFO_Out(&sRX_Buffer, &u8Temp);,对 count 递减 ...

谢谢,那有避免这个的解决方法吗?

出0入8汤圆

发表于 2021-2-2 16:07:19 | 显示全部楼层
mangolu 发表于 2021-2-2 16:05
谢谢,那有避免这个的解决方法吗?

舍弃 count 方案,
或者在非中断环境的操作中,对 count 的操作,关开中断。

出0入0汤圆

 楼主| 发表于 2021-2-2 16:10:14 来自手机 | 显示全部楼层
security 发表于 2021-2-2 16:07
舍弃 count 方案,
或者在非中断环境的操作中,对 count 的操作,关开中断。 ...

接收要用中断吧?不然还会丢失数据啊。楼上有说只记读写指针,但是如何判断缓存空还是满,好像比较麻烦吧?

出0入8汤圆

发表于 2021-2-2 16:17:14 | 显示全部楼层
mangolu 发表于 2021-2-2 16:10
接收要用中断吧?不然还会丢失数据啊。楼上有说只记读写指针,但是如何判断缓存空还是满,好像比较麻烦吧 ...

非中断的调用环境,例如 main 中的 count 操作,关开中断。

这要额外的判断逻辑,至于怎么解决,去网上查吧,之前给你 RT-Thread 的参考,就是一种实现。

出0入0汤圆

发表于 2021-2-2 16:28:26 | 显示全部楼层
security 发表于 2021-2-2 15:58
都会的,只不过,刚好避开了踩坑的时间点。

main 中的 FIFO_Out(&sRX_Buffer, &u8Temp);,对 count 递减 ...


因为count在xdata空间,操作count就不是原子操作。会有隐患。

出0入0汤圆

 楼主| 发表于 2021-2-2 16:37:02 来自手机 | 显示全部楼层
security 发表于 2021-2-2 16:17
非中断的调用环境,例如 main 中的 count 操作,关开中断。

这要额外的判断逻辑,至于怎么解决,去网上 ...

好的,谢谢

出0入0汤圆

发表于 2021-2-2 16:40:31 | 显示全部楼层
security 发表于 2021-2-2 16:07
舍弃 count 方案,
或者在非中断环境的操作中,对 count 的操作,关开中断。 ...

看了下汇编:
    25:                 (sFIFO->Count) ++;    // 存储数据字节数加1
C:0x01C6    8F82     MOV      DPL(0x82),R7
C:0x01C8    8E83     MOV      DPH(0x83),R6
C:0x01CA    E0       MOVX     A,@DPTR
C:0x01CB    04       INC      A
C:0x01CC    F0       MOVX     @DPTR,A

这里对count的操作,虽然不是一条语句完成。在中断时,会将用到的寄存器 压栈,出栈。木有问题。

出0入0汤圆

发表于 2021-2-2 17:08:41 | 显示全部楼层
在51mcu里操作u8类型的变量,在确保不发生溢出的情况下,不需要考虑临界变量问题。

出0入0汤圆

发表于 2021-2-2 18:26:13 | 显示全部楼层
修改代码,运行频率改为11.0592,115200BPS。串口一次发送01-----0f 共15个数据,100ms自动发送。不会丢数据。
上面的代码木问题。

可能是楼主的USB-串口问题。
我用的是CH340,自己画的板。前段时间在xx商城用15圆优惠券买了10片。

出0入442汤圆

发表于 2021-2-2 18:41:10 来自手机 | 显示全部楼层
mangolu 发表于 2021-2-2 12:23
初始:r = w = 0
读写各一个:r=1 w=1,此时不能说明为空吧?


因为fifo不超过256,因此读写指针是一个u8,不存在双字节操作,再加上一个pointer总是在中断里执行,因此不需要考虑冲突问题。很简单,a=(a+1)&(n-1)就行了。n一般是常数,取2的n次方便于计算。

出0入0汤圆

 楼主| 发表于 2021-2-2 18:44:17 来自手机 | 显示全部楼层
su33691 发表于 2021-2-2 18:26
修改代码,运行频率改为11.0592,115200BPS。串口一次发送01-----0f 共15个数据,100ms自动发送。不会丢数 ...

我这个是PL2303HX的,工具挺多,但是不在手上,我找另一个看看

出0入0汤圆

 楼主| 发表于 2021-2-2 18:47:28 来自手机 | 显示全部楼层
wye11083 发表于 2021-2-2 18:41
因为fifo不超过256,因此读写指针是一个u8,不存在双字节操作,再加上一个pointer总是在中断里执行,因此 ...

这个还需要想一下。我上面定义有超过256的指针。

出0入442汤圆

发表于 2021-2-2 20:27:10 来自手机 | 显示全部楼层
mangolu 发表于 2021-2-2 18:47
这个还需要想一下。我上面定义有超过256的指针。

fifo!数据缓存在你程序里面做!把串口做成服务!

出0入8汤圆

发表于 2021-2-2 23:53:47 来自手机 | 显示全部楼层
本帖最后由 security 于 2021-2-3 00:07 编辑
su33691 发表于 2021-2-2 16:40
看了下汇编:
    25:                 (sFIFO->Count) ++;    // 存储数据字节数加1
C:0x01C6    8F82  ...


中断本来就不会影响被中断任务的运行环境(换句话说,就是寄存器吧)。
这里的 count,不保护的话,一定会受并发的影响。

只是说,这种测试用例下,如果都是有序的踩准节拍,也就说,避开了并发访问的点,那么表面看起来,就是没有问题,但其实埋了个地雷,没踩到而已。

出0入0汤圆

 楼主| 发表于 2021-2-3 02:21:15 | 显示全部楼层
su33691 发表于 2021-2-2 18:26
修改代码,运行频率改为11.0592,115200BPS。串口一次发送01-----0f 共15个数据,100ms自动发送。不会丢数 ...

换了个串口,还是一样,证明不是串口芯片问题:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2021-2-3 07:22:15 | 显示全部楼层
这是我的测试:
使用STC8H1K08,运行频率11.0592MGZ,115200BPS,内部HC震荡器。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2021-2-3 07:35:16 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2021-2-3 10:26:25 来自手机 | 显示全部楼层
su33691 发表于 2021-2-3 07:35

估计程序逻辑问题不大,count冲突的逻辑也会有,我找其他板试试

出100入0汤圆

发表于 2021-2-3 11:04:26 | 显示全部楼层
本帖最后由 wqsjob 于 2021-2-3 11:08 编辑

缓存我一般用循环队列。不是FIFO。大小为64,128,256等。
比如51,我一般使用64字节缓存,比如转发功能如下


rx_interrupt()
{
    buf[rx_piont]=SBUF;
    rx_piont++;
    buf_num++;
    rx_point&0x3f;//0-63
   
}
//------------------
tx_interrupt()
{
  if(buf_num)
{
   buf_num--;
   tx_piont++;
tx_point&0x3f;//0-63
   SBUF=buf[tx_piont];
}
else
{
   tx_state=0;
}
}
//---------------------------------
tx_statrt()
{
  if(buf_num>63)
{
//  出错处理,一般为调用间隔太长导致
}
else
{
  if((buf_num>0)&&(0==tx_state)
{
  SBUF=buf[tx_piont];
tx_state=1;
}
}
}

//刚才写错了,RX和TX应该是一个函数里的。这个是不会同时操作buf_num的。如果是分开的,要考虑两个中断设置为同一优先级,排除这种情况。

出0入4汤圆

发表于 2021-2-3 11:37:42 | 显示全部楼层
FIFO_IN函数既在主函数调用,又在中断里调用,这儿可能会有bug。我记得标准的51这样调用会报错的。

出0入0汤圆

 楼主| 发表于 2021-2-3 12:16:35 来自手机 | 显示全部楼层
zqf441775525 发表于 2021-2-3 11:37
FIFO_IN函数既在主函数调用,又在中断里调用,这儿可能会有bug。我记得标准的51这样调用会报错的。 ...

设置为可重入就可以了

出0入4汤圆

发表于 2021-2-3 12:31:21 | 显示全部楼层
51有可重入函数保护机制吗?
我一定不会这么用。

出0入0汤圆

 楼主| 发表于 2021-2-5 14:44:49 | 显示全部楼层
wqsjob 发表于 2021-2-3 11:04
缓存我一般用循环队列。不是FIFO。大小为64,128,256等。
比如51,我一般使用64字节缓存,比如转发功能如 ...

今天有空把你的代码拿过来试了下,不懂得发送回来的为什么后面多一个数,并且是00 01这样变换:



还没仔细分析原因。代码如下:

  1. #define BUFFER_SIZE 64         // 缓存大小

  2. uint8_t u8Buffer[BUFFER_SIZE];        // 定义缓存
  3. uint8_t u8Front = 0;        // 读指针
  4. uint8_t u8Rear = 0;                // 写指针
  5. uint8_t u8Count = 0;        // 缓存存储字节计数

  6. uint8_t TX_State;

  7. void Uart_Send_Start(void);

  8. void main(void) {

  9.         Initial_System();        // 初始化系统

  10.         Uart_Send_String(UART1, "Uart1 Initial OK!");
  11.         Uart_Send_String(UART1, "\r\n");

  12.         while(1) {

  13.                 Uart_Send_Start();
  14.         }

  15. }

  16. /**
  17. * @brief  串口1中断处理
  18. *
  19. *
  20. * @par 函数说明:
  21. * 串口1中断处理,中断函数不需要声明。在其他应用中实现,要注释掉本函数。
  22. */
  23. void Uart1_ISR(void) interrupt 15 {        // 串口1中断向量为15
  24.         // uint8_t u8Temp1;

  25.         if (RI_1 == 1) {        // 接收中断
  26.                 clr_RI_1;        // 清接收中断,需手动清除

  27.                 /** 接收中断表示数据接收到,取串口缓存寄存器的值 */
  28.                 u8Buffer[u8Rear] = SBUF_1;
  29.                 u8Rear ++;
  30.                 u8Count ++;
  31.                 u8Rear &= 0x3F;        // 0-63
  32.         }

  33.         if(TI_1 == 1) {        // 发送中断
  34.                 clr_TI_1;        // 清发送中断,需手动清除

  35.                 /** 发送中断表示数据发送完成,清忙标志 */
  36.                 if(u8Count > 0) {
  37.                         u8Count --;
  38.                         u8Front ++;
  39.                         SBUF_1 = u8Buffer[u8Front];
  40.                         u8Front &= 0x3F;        // 0-63
  41.                 } else {
  42.                         TX_State = 0;
  43.                 }
  44.         }
  45. }

  46. void Uart_Send_Start(void) {
  47.         if(u8Count > 63) {
  48.                 // 出错处理,一般为调用间隔太长导致
  49.         } else {
  50.                 if((u8Count > 0) && (TX_State == 0)) {
  51.                         SBUF_1 = u8Buffer[u8Front];
  52.                         // u8Count --;
  53.                         // u8Front --;
  54.                         TX_State = 1;
  55.                 }
  56.         }
  57. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2021-2-5 14:56:59 | 显示全部楼层
哦,我改成下面这样好了:

  1. void Uart_Send_Start(void) {
  2.         if(u8Count > 63) {
  3.                 // 出错处理,一般为调用间隔太长导致
  4.         } else {
  5.                 if((u8Count > 0) && (TX_State == 0)) {
  6.                         SBUF_1 = u8Buffer[u8Front];
  7.                         u8Count --;
  8.                         u8Front ++;
  9.                         TX_State = 1;
  10.                 }
  11.         }
  12. }
复制代码




其实这个跟我的差不多,只是Count是在中断里更改,不会造成同时有Count变化的情况出现,所以不会出错。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2021-2-5 16:27:33 | 显示全部楼层
mangolu 发表于 2021-2-5 14:56
哦,我改成下面这样好了:

谈一下我的看法:


1. N76E003这颗芯片很烂 ,还不如STC12,
        STC的51, 在经过STC15和STC8两代优化,指令效率很高。
2. 在51MCU使用指针,最好是使用基于存储器的指针。

出0入0汤圆

 楼主| 发表于 2021-2-5 16:44:25 | 显示全部楼层
su33691 发表于 2021-2-5 16:27
谈一下我的看法:

正在跑看,目前感觉没出问题。不过发现同时使用串口0和串口1出问题,网上说了几个方法,我现在还没有测试,目前只用到一个串口。至于你说的基于存储器的指针我不大明白,我上面有定义的xdata FIFO buffer这样的是基于存储器的指针吗?

出0入0汤圆

发表于 2021-2-5 16:47:59 | 显示全部楼层
基于存储器的指针:

void FIFO_Out(FIFO xdata *sFIFO, uint8_t data *u8pData);

出0入0汤圆

 楼主| 发表于 2021-2-5 17:01:16 | 显示全部楼层
su33691 发表于 2021-2-5 16:47
基于存储器的指针:

void FIFO_Out(FIFO xdata *sFIFO, uint8_t data *u8pData);

哦,谢谢!我看一下

出0入0汤圆

发表于 2021-2-5 17:10:45 | 显示全部楼层
115200波特率发送一个字节需80US左右

fifo变量位于xdata空间,运行效率很低。
收发一个字节要运行2次fifo_in和2次 fifo_out。
如果使用一般指针,在80US,大循环跑不了一遍,count变量在前后台均在改变的隐患就会成为真正的BUG.

出0入0汤圆

 楼主| 发表于 2021-2-5 17:45:37 | 显示全部楼层
su33691 发表于 2021-2-5 17:10
115200波特率发送一个字节需80US左右

fifo变量位于xdata空间,运行效率很低。

这个单片机是1T的,运行在16.6MHz下,一个机器周期是1/16.6 = 0.06US,这个关系应该不大吧?

出0入0汤圆

发表于 2021-2-5 17:50:31 | 显示全部楼层
mangolu 发表于 2021-2-5 17:45
这个单片机是1T的,运行在16.6MHz下,一个机器周期是1/16.6 = 0.06US,这个关系应该不大吧? ...

STC12也号称1T的。STC8的指令速度比STC12快2.5x
呵呵。

出100入0汤圆

发表于 2021-2-6 15:45:22 | 显示全部楼层
mangolu 发表于 2021-2-5 14:56
哦,我改成下面这样好了:

嗯,问题的确出在这里。相当于中断中多判断了一次。
中断程序把这两行提到if语句之前应该就可以了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 00:05

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表