打印

单片机高手请进!keil BUG至于你信不信,反正我是信了!

[复制链接]
3875|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ARM_Lover|  楼主 | 2011-8-16 12:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ARM_Lover 于 2011-8-16 12:54 编辑

我不知到这到底是是为什么?莫非KeilC有BUG?我想那可能行太小了。但我还是不知道到底是为什么?请那位高高手指点一二!我想知道此问题的一定是高手中的高手!程序原本很大,但是最后我把原因缩小到最小,把程序压缩到了最小,以便各位高手方便查阅!另外需要说明的是,如果吧所有的idata去掉的话,就没有该问题了!:dizzy:
大家可以用任何一个51开发板(如果不是STC11F08XE系列,只需要吧串口初始化略加修改便是了!)都可以进行测试,结果会让你们大吃一惊!原来、可以这样。至于你们信不信,反正我是信了!
对了,你需要吧中断0 引脚与串口接收引脚接起来!我的硬件就那样设计的!
#include "STC11F.H"
#include "config.h"
sbit LED =P0^3;
bit flag_modle0 = 0;
uint8 idata REBUF[20];
uint8 idata data_buffer[20] = "0123456789\n";
//串口初始化
void SerialInit(void)
{
AUXR = 0x11; //STC11F08XE配置
BRT = 0xFD; //启用独立波特率发生器
SCON = 0x50; //工作方式为1,允许接受
PCON = 0x00; //SMOD=0
}
//中断初始化
void InterruptInit(void)
{
IT0 = 1;
EX0 = 1;
AUXR1 = 0x00;
EA = 1;
}
//发送一个字节
void SendByte(const uint8 byte)
{
SBUF = byte;
while(TI == 0);
TI = 0;
}
//从idata区域,发送一个字符串
void SendStr(const uint8 idata * ptr)
{
while(*ptr != '\0')
{
SBUF = *ptr;
while(TI == 0);
TI = 0;
ptr++;
}
}
//获取一个字符串,如“::000300!” ,并存放在idata区域里
uint8 * Gets(uint8 idata *str)
{
while(1)
{
while(RI == 0);
RI = 0;
if(SBUF == '!'){
*str = SBUF;
str++;
*str = '\0';
break;
}
*str = SBUF;
str++;
}
return str;
}

void Puts(uint8 code * ptr)
{
while(*ptr != '\0'){
SBUF = *ptr;
while(TI == 0);
TI = 0;
ptr++;
}
}
//中断0
void Int0() interrupt 0 using 1
{
EX0 = 0;
AUXR1 = 0x00;
if(flag_modle0 == 0) //如果发送模式未定,进入未知接受状态
{
while(RI == 0);
RI = 0;
if(SBUF == ':')
{
uint8 idata *sp = REBUF;
uint8 idata *ep = Gets(sp);
LED = ~LED;
//输入字符串::000300!
//SendStr(strp++)能够正常执行,但是SendByte(*sp)发送结果为'\0',输出"\nCommand Error!\n"
// SendByte(*sp);
// SendByte(*(sp+1));
// SendByte(*(sp+2));
//SendStr(strp++)能够正常执行,SendStr(sp+1) 与SendStr(sp+2)的发送结果与输入的结果一样。
// SendStr(sp+1);
// SendStr(sp+2);
// SendStr(sp+3);
//SendStr(strp++)没有发送结果,SendStr(sp+1)没有发送结果,输出"\nCommand Error!\n"
// SendStr(sp++);
// SendStr(sp++);
// SendStr(sp++);
if(*sp == ':') //:: /ip/mod/boad/!
Puts("Command Right!\n");
else
Puts("\nCommand Error!\n");
}
IE0 = 0;
EX0 = 1;
}
}
void main(void)
{
uint8 *strp = data_buffer;
SerialInit();
InterruptInit();
SendStr(strp++);
SendStr(strp++);
SendStr(strp++);
SendStr(strp++);
while(1);
}

相关帖子

沙发
DownCloud| | 2011-8-16 13:03 | 只看该作者
没把问题说清楚。所以帮不了你。大概看了你的串口程序,这样的程序是不能用的。

使用特权

评论回复
板凳
ARM_Lover|  楼主 | 2011-8-16 13:34 | 只看该作者
2# DownCloud 原因是这样的。我需要对单片机通过串口进行配置一些参数,但是发送命令是说错误,即程序里面Puts("\nCommand Error!\n");。于是我让单片机把程序受到的内容发出来,结果发现了这一系列的问题。在中断程序里面有三段
1、输入这句话

   SendByte(*sp);
   SendByte(*(sp+1));
   SendByte(*(sp+2));
   输出结果:
   0123456789
   123456789
   23456789
   3456789
   Command Error!
2、输入这3句程序
   SendStr(sp+1);
   SendStr(sp+2);
   SendStr(sp+3);
   输出结果:
   0123456789
   123456789
   23456789
   3456789
   :000300!:000300!:000300!
   Command Error!

3、输入这3句
   SendStr(sp++);
   SendStr(sp++);
   SendStr(sp++);
   输出结果

Command Error!

这下可够明白了么?
不知高手能否给予解答?
我实在是疑惑不解啊??、

使用特权

评论回复
地板
mohanwei| | 2011-8-16 14:40 | 只看该作者
能写出这样的极品程序,当然会疑惑不解了……:lol
建议把代码格式化一下;串口中断只干两个事:把SBUF的数据搬到接收FIFO,把发送FIFO的数据搬到SBUF;命令的拆解和解释执行都放到main函数的主循环里。

使用特权

评论回复
5
ARM_Lover|  楼主 | 2011-8-16 15:16 | 只看该作者
4# mohanwei 我那只是个调试部分,我给你们呈现的是调试出现的现象!我把所有的程序原样搬上去,你们有心思看么?

使用特权

评论回复
6
DownCloud| | 2011-8-16 16:01 | 只看该作者
3# ARM_Lover
嘿嘿,看不懂,帮不了你。程序浪费的CPU时间太多了。接收不能用死等的方式。发送用死等的方式也不好。

使用特权

评论回复
7
alicedodo| | 2011-8-16 16:32 | 只看该作者
main()和ISR都调用了SendStr(),而SendStr()没有声明为可重入,LZ编译时没遇到警告么?

看样子好像是指针传递出了问题, 试试这个方法行不行:修改一下编译设置,
options for target'XXX' (就是那个能设置晶振频率的选项卡)---> C51 ---> code optimization--->选中 don't use absolute register access

使用特权

评论回复
8
ARM_Lover|  楼主 | 2011-8-16 16:44 | 只看该作者
6# DownCloud 你的意思我是明白的!我平常的程序也也是基于中断的,但是现在我面对的不是效率,也不是方法。而是为什么寻址会发生错误!这才是真正要解决的问题!我在刚发帖的时候就预料到很多朋友会抓住我的这个问题不放,我想大家是本末倒置,或者曲解了我的意思!在C程序效率我还是比较有自信的的。毕竟我用汇编写了1年的程序,对51结构还是相当的熟悉的!

使用特权

评论回复
9
ARM_Lover|  楼主 | 2011-8-16 16:53 | 只看该作者
7# alicedodo 我感觉这位仁兄的见解还是比较切入主题的。但是在一般的情况下,不可重入函数易导致的错误在我这个调试函数里面是不会发生的。因为,首先上电后,程序马上运行了四次SendStr();(这个函数当然是非常快的,还来不及让我发送数据)。然后一直在while(1);等待过程,直到中断产生。之后不会被调用,也就不会因中断调用SendStr();而产生不可重入函数引发的错误。

使用特权

评论回复
10
alicedodo| | 2011-8-16 21:53 | 只看该作者
上面和LZ说的一共是两个问题:
1、main()和ISR共同调用非可重入函数可能导致的错误

2、Lz程序里有个返回指针的函数,我觉得问题也可能出在这儿。C代码编译成汇编之后,程序使用寄存器返回指针值。当代码优化级别比较高的时候,编译器默认BANK0寄存器组,那么寻址寄存器的时候会直接用绝对地址,比如说寻址R6,汇编代码可能是MOV 0x06,A这个样子的。
如果ISR使用了非BANK0寄存器组,且代码中调用了返回指针的函数,因为上面的原因,就会出现数据丢失的情况。

上面的第2种情况我以前遇到过,使能don't use absolute register access选项就能解决这个问题。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
ARM_Lover + 1
11
huangqi412| | 2011-8-16 23:06 | 只看该作者
既然都汇编这么精通,为啥不看看汇编窗口分析一下。。。

使用特权

评论回复
12
ARM_Lover|  楼主 | 2011-8-16 23:15 | 只看该作者
10# alicedodo 我想应该是你说的问题!但不一定是你说的返回指针的问题。我正在看反汇编,一定要找到问题的根源。

使用特权

评论回复
13
autopccopy| | 2011-8-17 03:06 | 只看该作者
不懂!这是一个奇迹?

使用特权

评论回复
14
mcu5i51| | 2011-8-17 08:47 | 只看该作者
void SendStr(const uint8 idata * ptr)
代码中多次使用这样的声明方式,可以最大限度的提高效率;
副作用是 const预示着你不能用任何可以改变的变量作为参数

使用特权

评论回复
15
arlisssenlia| | 2011-8-17 09:25 | 只看该作者
不懂

使用特权

评论回复
16
jiemnij| | 2011-8-17 11:03 | 只看该作者
这个代码..看的云里雾里的..
uint8 * Gets(uint8 idata *str)
这个前后指针类型都不统一.
如果去掉idata ..至少类型统一 了,,,当然未必是这个问题..
但是至少写的时候..应该要避免这个情况吧..
idata * 是 1byte的玩意,,, 但是 * 可是 3byte的 数据..

使用特权

评论回复
17
ARM_Lover|  楼主 | 2011-8-17 11:21 | 只看该作者
16# jiemnij 是啊,因为我见了很多调试的程序,所以让人感到困惑!我把最精简的代码发上去!是这样的,我给串口发送“::000300!”字符串,但是结果却是输出“Command Error!);
”,所以我加了很多的调试程序,结果出现了更多的奇怪的现象,就是上面代码里面的问题。
但是至于idata的肯定是没问题的,因为我用到全是idata*。这样效率会很高的!
#include "STC11F.H"
#include "config.h"
sbit LED =P0^3;
bit flag_modle0 = 0;
bit flag_rec = 0;
uint8 temp = 0;
uint8 idata REBUF[20];
uint8 idata data_buffer[20] = "0123456789\n";
//串口初始化
void SerialInit(void)
{
AUXR = 0x11; //STC11F08XE配置
BRT = 0xFD; //启用独立波特率发生器
SCON = 0x50; //工作方式为1,允许接受
PCON = 0x00; //SMOD=0
}
//中断初始化
void InterruptInit(void)
{
IT0 = 1;
EX0 = 1;
AUXR1 = 0x00;
EA = 1;
}
//发送一个字节
void SendByte(const uint8 byte)
{
SBUF = byte;
while(TI == 0);
TI = 0;
}
//从idata区域,发送一个字符串
//获取一个字符串,如“::000300!” ,并存放在idata区域里
uint8 * Gets(uint8 idata *str)
{
while(1)
{
while(RI == 0);
RI = 0;
if(SBUF == '!'){
*str = SBUF;
str++;
*str = '\0';
break;
}
*str = SBUF;
str++;
}
return str;
}

void Puts(uint8 code * ptr)
{
while(*ptr != '\0'){
SBUF = *ptr;
while(TI == 0);
TI = 0;
ptr++;
}
}
//中断0
void Int0() interrupt 0 using 1
{
EX0 = 0;
AUXR1 = 0x00;
if(flag_modle0 == 0) //如果发送模式未定,进入未知接受状态
{
while(RI == 0);
RI = 0;
if(SBUF == ':')
{
uint8 idata *spp = REBUF;
uint8 idata ep = Gets(spp);
if(*spp == '1')
Puts("Command Right!\n");
else
Puts("\nCommand Error!\n");
}
IE0 = 0;
EX0 = 1;
}
}

void main(void)
{
uint8 idata *strp = data_buffer;
SerialInit();
InterruptInit();
while(1);
}

使用特权

评论回复
18
jiemnij| | 2011-8-17 11:43 | 只看该作者
本帖最后由 jiemnij 于 2011-8-17 11:54 编辑

//发送一个字节
void SendByte(const uint8 byte)
{
SBUF = byte;
while(TI == 0);
TI = 0;
}

   SendByte(*sp);
   SendByte(*(sp+1));
   SendByte(*(sp+2));
   输出结果:
   0123456789
   123456789
   23456789
   3456789
   Command Error!

你只发送一个字节...结果出来字符串..肯定不会的
多半你调试那里.弄错了..或者你原先用sendstr 等函数的..编译后没烧写等等的..
另外你这种问题..最好把问题细化一下..我是看不明白.你到底想要表达的是keil有什么bug

一般情况下,调试出现异常 ,首先怀疑一下自己的代码有没有问题.
编译器出错的概率是非常非常小的..99.9%的情况都是代码问题
就像上面的SendByte 我非常怀疑输出结果

另外调试的时候..你最好先单字节输出结果看看为妙...先把问题细化再说

使用特权

评论回复
19
ARM_Lover|  楼主 | 2011-8-17 13:37 | 只看该作者
18# jiemnij SendByte();发送的是十六进制0,结果在串口里面一ASCII的形式显示不出来。而
Command Error!则是下面那个if……else……发送出来的。

使用特权

评论回复
20
ARM_Lover|  楼主 | 2011-8-21 15:58 | 只看该作者
哎,看来是没人愿意看着问题了。我还是把帖结了呗。实际上好几天前就把问题解决了,可是我还是想看看高手们的见解也意见。结果没人愿意理!问题就是不可重入函数造成的。中断调用了一个不可重入函数,造成了错误,结果我有调用另外一个不可重入函数去调试,结果造成了很对稀奇古怪的现象。不过还是感谢大家的发言。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

54

帖子

1

粉丝