OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3879|回复: 9

怎样实现多任务串口打印?

[复制链接]

44

主题

225

帖子

0

精华

高级会员

Rank: 4

积分
658
金钱
658
注册时间
2013-11-22
在线时间
131 小时
发表于 2016-1-6 15:47:01 | 显示全部楼层 |阅读模式
想实现在多个任务中调用串口打印,要求不能乱码,也就是每个任务中的字符都能完整的打印出来,目前还没有思路,大家帮忙想想
该怎么实现?



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-1-6 15:59:01 来自手机 | 显示全部楼层
缓冲+定时打印

大致原理是,调用打印函数时将带打印的数据copy到缓冲里,然后直接返回

单片机再定时检测缓冲是否为空,非空则将内容发送,

缓冲大小需要谨慎选择
回复 支持 反对

使用道具 举报

44

主题

225

帖子

0

精华

高级会员

Rank: 4

积分
658
金钱
658
注册时间
2013-11-22
在线时间
131 小时
 楼主| 发表于 2016-1-6 16:07:16 | 显示全部楼层
xkwy 发表于 2016-1-6 15:59
缓冲+定时打印

大致原理是,调用打印函数时将带打印的数据copy到缓冲里,然后直接返回

[mw_shl_code=applescript,true]
/***********************队列管理代码*************************/
#define QUEUE_CIRCULAR_BUF_SIZE 200        //队列循环缓冲buf长度  ,最多支持的同时打印队列长度
#define PRINT_IF_BLOCK                        0    //打印输出是否允许阻塞; 1,阻塞方式;0,非阻塞方式  ,最好不用阻塞模式

static unsigned char xdata queue_circular_buf[QUEUE_CIRCULAR_BUF_SIZE] = {0};  //队列循环缓冲 数组
static unsigned char xdata queue_front = 0;      //队列头部
static unsigned char xdata queue_back = 0;       //队列尾部
static unsigned char xdata queue_size = 0;       //队列有效元素大小

//队列初始化
static void queue_circular_buf_init(void)
{
    queue_front = 0;   //队头索引清零
    queue_back = 0;    //队尾索引清零
    queue_size = 0;    //队长(chang)清零
}

//入队
static void queue_circular_buf_push(unsigned char indata)
{                    
    queue_circular_buf[queue_back] = indata;  //存储数据
   
    queue_back++;                             //队尾变化
    if(QUEUE_CIRCULAR_BUF_SIZE == queue_back)
    {
        queue_back = 0;   
    }

    queue_size++;                             //有效长度自增
}

//出队
static  unsigned char queue_circular_buf_pop(void)
{           
    unsigned char   outdata = queue_circular_buf[queue_front];  //取出数据  
   
    queue_front++;                             //队头变化
    if(QUEUE_CIRCULAR_BUF_SIZE == queue_front)
    {
        queue_front = 0;   
    }

    queue_size--;                              //有效长度自减

    return outdata;
}

//判空,空返回1,非空返回0
static unsigned char queue_circular_buf_empty(void)
{           
    if(queue_size)
    {
        return 0;
    }                           

    return 1;
}

//判满,满返回1,非满返回0
static unsigned char queue_circular_buf_full(void)
{           
    if(QUEUE_CIRCULAR_BUF_SIZE == queue_size)
    {
        return 1;
    }                           

    return 0;
}

/***********************队列管理代码**尾***********************/

//串口0打印,将数据放在打印缓冲区,启动发送
void uart0_print(const unsigned char *buf, unsigned char len)
{
        unsigned char *temp_buf = buf;
        CRITICAL_ENTER;    //关闭总中断

#if  PRINT_IF_BLOCK   //如果是阻塞模 式      
        while (len--)
        {
                while (queue_circular_buf_full())   //
                {
                        task_sleep(2); //系统延时
                }

                queue_circular_buf_push(*temp_buf);  //队列未满,数据入队列

                temp_buf++;
        }

#else                 //如果是非阻塞模式   
        while (len--)
        {
                if (queue_circular_buf_full())
                {
                        CRITICAL_EXIT;
                        return;//队列已满
                }
                else
                {
                        queue_circular_buf_push(*temp_buf);  //队列未满,数据入队列
                }
                temp_buf++;
        }

#endif               
        CRITICAL_EXIT; //打开总中断

        TI = 1;//启动发送
}

//串口中断服务函数,不断的从队列中取出数据打印
void uart0_isr() interrupt 4  using 2
{
        if (TI)                                     //如果是发送中断事件
        {
                if (!queue_circular_buf_empty())        //非空
                {
                        S0BUF = queue_circular_buf_pop();  //出队列       
                }

                TI = 0;
        }
        if (RI)
                RI = 0;
}[/mw_shl_code]
回复 支持 反对

使用道具 举报

44

主题

225

帖子

0

精华

高级会员

Rank: 4

积分
658
金钱
658
注册时间
2013-11-22
在线时间
131 小时
 楼主| 发表于 2016-1-6 16:10:25 | 显示全部楼层
xkwy 发表于 2016-1-6 15:59
缓冲+定时打印

大致原理是,调用打印函数时将带打印的数据copy到缓冲里,然后直接返回

你好,感谢你的回答,我做的思路也是向你说的那样,每个打印任务只负责将数据copy到全局循环缓冲队列,我这里的缓冲定义大小是200,拷贝完毕后,启动串口中断发送;问题是现在这样用,还是会乱码?不知什么原因?如果有空的话麻烦帮忙看看?
回复 支持 反对

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-1-6 16:43:01 | 显示全部楼层
可能因为读写冲突,读和写同时操作一个缓冲可能会出错,你可以试着用双缓冲,或做读写分离,或者给缓冲区加锁防止写的时候读(或读的时候写)
坚决不用寄存器,拒绝重复造轮子。
回复 支持 反对

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-1-6 16:48:34 | 显示全部楼层
你入队的时候没有考虑入指针追上出指针
坚决不用寄存器,拒绝重复造轮子。
回复 支持 反对

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-1-6 16:50:11 | 显示全部楼层
还有,queue_size这个变量没有多大意义,我在做循环队列缓冲时候,都是通过对比top和bottom指针是否相等来判断缓冲是否为空(舍弃最远值型缓冲)
坚决不用寄存器,拒绝重复造轮子。
回复 支持 反对

使用道具 举报

44

主题

225

帖子

0

精华

高级会员

Rank: 4

积分
658
金钱
658
注册时间
2013-11-22
在线时间
131 小时
 楼主| 发表于 2016-1-6 17:04:39 | 显示全部楼层
queue_size变量用着是为了方便,其实也可以判断头尾,我程序当中,都判断了 不满才入队列,不空才出队列的
回复 支持 反对

使用道具 举报

44

主题

225

帖子

0

精华

高级会员

Rank: 4

积分
658
金钱
658
注册时间
2013-11-22
在线时间
131 小时
 楼主| 发表于 2016-1-6 17:06:20 | 显示全部楼层
xkwy 发表于 2016-1-6 16:50
还有,queue_size这个变量没有多大意义,我在做循环队列缓冲时候,都是通过对比top和bottom指针是否相等来 ...

入队和出队只做自己的事情,但在做这件事件之前,我都判断是否为空,是否未满?感觉没有问题?
回复 支持 反对

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-1-6 17:30:35 | 显示全部楼层
你试试用双缓冲,做读写分离,还有,发送别放在中断里,用定时发送,等待TI标志位

坚决不用寄存器,拒绝重复造轮子。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 13:24

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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