一乐电子

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 1890|回复: 9

[其他综合] 这个串口中断如何处理才好?

[复制链接]
发表于 2014-8-22 22:29 | 显示全部楼层 |阅读模式
本帖最后由 gongzhu 于 2014-8-22 22:32 编辑

做个数码管显示的万年历程序,综合了两个程序:
程序1,读取DS3231时间数据并显示到数码管,没有问题;
程序2,读取串口gps时间数据并显示到数码管,也没有问题。

现将程序1、2合并,同时读取DS3231和串口GPS数据并发送至数码管显示,开始运行正常,运行一段(不固定)时间后死机。
知道是中断处理上的问题,便给main()和串口接收加上了中断开关ES信号,这下不会死机了,可是gps的时间显示每隔4、5秒会停顿一秒,下一秒后又会正常运行几秒,如此循环(不知是否能用“跳秒”描述),而DS3231的数据则正常更新显示。
因第一次碰到,不懂如何处理。

主要程序如下:

void GetDS3231();  //读取DS3231数据,并处理农历、星期
void Send2Led();   //驱动Max7219更新数码管数据,含DS3231和GPS的时间数据
void FormatString(char *p,uchar len);//格式化GPRMC字符串,把时间、日期传递给全局变量

main()//主函数:100ms循环调用GetDS3231() ,发现数据有更新则刷新Max7219更新数码管数据
{
    uchar T=0;//判断秒有无更新,防止过快刷新数码管驱动芯片max7219
    init(); //系统初始化
    InitBps();//串口初始化

    while(1)//进入无限循环
    {
        if(w == 0)         //运行模式
        {
            ES = 0; //中断关
           GetDS3231();        //读取DS3231时间数据
            ES = 1;//中断开
            if(T != Dstime[0])
            {
                Send2Led();//更新数码管数据
                T = Dstime[0];
            }
            //ES = 1;//中断开放在此处运行效果一样
            DelayMS(100); //一定得延时,否则串口不能正常接收数据
        }
        else
        {}
        //检测按键设置时间略
    }
}

GetRs232_Data() interrupt 4   //串口中断读取GPS数据,截取GPRMC数据串并处理出时间日期数据
{
    uchar tmp, i;
    ES = 0;//中断关
    if(RI)
    {
        tmp = SBUF;
        switch(tmp)
        {
        case '$':
            mode = 1;                //接收命令模式
            byte_count = 0;          //接收位数清空
            memset(RsBuf, 0, 80);
            RsBuf[byte_count++] = tmp;
            break;
        case '\r':                           
            if(mode == 2)
                buf_full = 1;
            else
                buf_full = 0;
            mode = 0;
            RsBuf[byte_count] = '\0';
            break;
        default:
            if(mode == 1)
            {
                //命令种类判断
                RsBuf[byte_count] = tmp;                //接收字符放入类型缓存
                if(byte_count == 5)                     //如果类型数据接收完毕,判断类型
                {
                    if(RsBuf[1] == 'G' && RsBuf[2] == 'P' && RsBuf[3] == 'R')
                    {
                        if(RsBuf[4] == 'M' && RsBuf[5] == 'C')
                        {
                            mode = 2;   /** 获取标志头 $GPRMC        缓存可以接收后续字符 **/
                        }
                        else
                        {
                            mode = 0;
                            byte_count = 0;
                        }
                    }
                    else
                    {
                        mode = 0;
                        byte_count = 0;
                    }
                }

                byte_count++;
            }
            else if(mode == 2)
            {
                RsBuf[byte_count] = tmp;
                byte_count++;
            }

            if(byte_count > 73)         /** 接收数据过长,超过73Byte还没标志尾抛弃 **/
            {
                mode = 0;
                byte_count = 0;
                memset(RsBuf, 0, 80);
            }
            break;
        }
        if(buf_full && byte_count > 36 && Checksum(RsBuf, byte_count))         // 标志头尾齐全、至少有时间日期数据、异或校验无误,才能解析数据
        {
            FormatString(RsBuf, byte_count);//格式化GPRMC字符串,把时间、日期传递给全局变量
            buf_full = 0;
        }
    }
    RI = 0;
    ES = 1;//中断开
}


补充,GPS通信协议:9600,N,8,1 ;每秒发送一次,总数据525字节左右,如下:
$GPRMC,060323.00,A,3333.87334,N,11859.00314,E,0.087,353.41,180814,,,A*68
$GPVTG,353.41,T,,M,0.087,N,0.162,K,A*37
$GPGGA,060323.00,3333.87334,N,11859.00314,E,1,4,16.63,-18.5,M,4.9,M,,*7B
$GPGSA,A,3,28,01,11,17,,,,,,,,,18.83,16.63,8.83*0C
$GPGSV,3,1,12,28,73,325,36,01,57,039,39,04,69,241,,11,36,051,37*7D
$GPGSV,3,2,12,20,44,130,,17,39,300,39,30,32,216,,32,31,075,*78
$GPGSV,3,3,12,08,20,194,,06,12,230,,07,12,190,,19,06,081,*73
$GPGLL,3333.87334,N,11859.00314,E,060323.00,A,A*64
$GPZDA,060323.00,18,08,2014,00,00*64



发表于 2014-8-22 23:13 | 显示全部楼层
你怎么理解ISR要求尽可能写的短小精悍?
比如一般做法是:串口中断只负责接收并保留数据,至于报文解析则通过标志位异步交给主循环调用相应的报文解析。
主循环一般啥事都不干,就是查看标志位,然后进模块。

当然,碰上多个独立任务有可能抢cpu的时候,还要同步处理一下,总体考虑差不多了才写代码。

点评

正解,这个思路很好,我一直在用  发表于 2014-8-23 06:49
回复

使用道具 举报

发表于 2014-8-23 01:37 | 显示全部楼层
GPS如果只取时间的话,建议关闭GPS没用的报文。
回复

使用道具 举报

发表于 2014-8-23 07:34 来自手机 | 显示全部楼层
GPSдRTCоУ
回复

使用道具 举报

发表于 2014-8-23 07:36 | 显示全部楼层
一天获取一次GPS时间写RTC芯片做校正就足够了,没必要两者同时读取

点评

我是顺便测3231的误差如何,可随时对比查看。折腾中  发表于 2014-8-23 13:43
回复

使用道具 举报

发表于 2014-8-23 08:37 | 显示全部楼层
benli 发表于 2014-8-23 07:36
一天获取一次GPS时间写RTC芯片做校正就足够了,没必要两者同时读取

强烈赞同!………………
回复

使用道具 举报

 楼主| 发表于 2014-8-23 13:46 | 显示全部楼层
40560335 发表于 2014-8-23 01:37
GPS如果只取时间的话,建议关闭GPS没用的报文。

GPS固定格式发送的,暂没法刷机让它只发时间报文。
正因为无关时间日期的“垃圾”数据太多,占用了太多资源。
现按2楼说明,串口中断只截取数据,解析放到main中处理,挂机测试中
回复

使用道具 举报

发表于 2014-8-23 20:51 | 显示全部楼层
可以让,这俩交替显示啊。这样应该不会出现单片机处理不过来的问题了。
回复

使用道具 举报

本版积分规则

QQ|一淘宝店|手机版|商店|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2025-10-31 12:25 , Processed in 0.044954 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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