科研报告2

FLY 竹蜻蜓


2015-09-05

今天找出了之前的一个bug,把遥控器的NRF24L01和小飞机的NRF24L01模块调通了。

问题原因:

把NRF24L01_Check()检测NRF24L01是否在位的程序放在了NRF24L01_TX_Mode()设置为发送模式之后。

问题分析:

  • NRF24L01_Check() 代码:
1
2
3
4
5
6
7
8
9
10
11
12

u8 NRF24L01_Check(void)
{
u8 buf[5] = {0XA5, 0XA5, 0XA5, 0XA5, 0XA5};
u8 i;
SPI2_SetSpeed(SPI_BaudRatePrescaler_4);
NRF24L01_Write_Buf(WRITE_REG_NRF + TX_ADDR, buf, 5);//这里设置发送地址为0XA5
NRF24L01_Read_Buf(TX_ADDR, buf, 5);
for (i = 0; i < 5; i++)if (buf[i] != 0XA5)break;
if (i != 5)return 1;
return 0;
}
  • NRF24L01_TX_Mode()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const u8 TX_ADDRESS[TX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10, 0x01}; //发送地址
const u8 RX_ADDRESS[RX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10, 0x01}; //发送地址
void NRF24L01_TX_Mode(void)
{
NRF24L01_CE = 0;
NRF24L01_Write_Buf(WRITE_REG_NRF + TX_ADDR, (u8*)TX_ADDRESS, TX_ADR_WIDTH);//这里设置发送地址为正确的地址。只有发送地址和接收地址相配对,才能通信成功。
NRF24L01_Write_Buf(WRITE_REG_NRF + RX_ADDR_P0, (u8*)RX_ADDRESS, RX_ADR_WIDTH);
NRF24L01_Write_Reg(WRITE_REG_NRF + EN_AA, 0x01);
NRF24L01_Write_Reg(WRITE_REG_NRF + EN_RXADDR, 0x01);
NRF24L01_Write_Reg(WRITE_REG_NRF + SETUP_RETR, 0x1a);
NRF24L01_Write_Reg(WRITE_REG_NRF + RF_CH, 40);
NRF24L01_Write_Reg(WRITE_REG_NRF + RF_SETUP, 0x0f);
NRF24L01_Write_Reg(WRITE_REG_NRF + CONFIG, 0x0e);
NRF24L01_CE = 1;
}
  • 正确的主函数
1
2
3
4
5
6
7
while (NRF24L01_Check())//如果这句放在设置发送模式的后面,就会把用来测试的发送地址设为真正的发送地址,覆盖掉正确的发送地址。从而导致通信失败。    
{
LED2_ON;
LED1_OFF;
printf("no");
}
NRF24L01_TX_Mode();

2015-09-08

今天遭遇了一个神奇的bug:

一个简单的按键扫描程序,就俩键。

逻辑是:

1
2
3
4
5
6
7
8
9
10
11
12
u8 key_scan(void)
{
if(有键按下:按键1按下||按键2按下)
{
if(按键1按下)
return 1;
else if(按键2按下)
return 2;
}
else//无键按下
return 0;
}

在主程序中:

1
2
3
4
5
6
7
8
9
key = key_scan();
if(key == 1)
{
do a;
}
if(key == 2)
{
do b;
}

表面上看没错误,实际有一个很明显的漏洞:当if……else if…… 不包括所有的条件在内,也就是说有可能会出现条件不符合if(……),也不符合else if(……)的情况,这时候函数就不知道该返回什么值了。就隐藏了一个潜在的无用返回值,很有可能影响正常的程序。比如这个无用返回值是1,这样主程序会误认为按下了按键1,执行了a。

事实也确实是如此:
warning
它有一个无返回值的警告。然而我没在意,但程序运行时出现这样的情况:

实例描述:
按键扫描函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
u8 KEY_scan(void)
{
if(MODE_KEY==0||FUN_KEY==0)
{
delay_ms(10);
if(MODE_KEY==0)
return 1;
else if(FUN_KEY==0)
return 2;
}
else
return 0;
}

主函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define MODE_KEY_DOWN 1
#define FUN_KEY_DOWN 2

while(1)
{
key = KEY_scan();

if(key>0)
{
if (key==MODE_KEY_DOWN)//按下MODE键
{
printf("MODE_KEY\n");//打印MODE_KEY
key=0;
}
else if (key==FUN_KEY_DOWN)//按下FUN键
{
printf("FUN_KEY\n");//打印FUN_KEY
key=0;
}
}
}

end1

运行结果:
当我按下FUN键后,会莫名出现一个MODE键按下的对应打印。
debug发现,当按下FUN键后,key值变为2,当松开的一瞬间,突然有一个key=1的值出现,导致程序执行了打印MODE_KEY,但是程序并没有执行到if(MODE_KEY==0)这句判断语句内,但还是返回了一个1值。这个就是垃圾返回值。

把程序修改成了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
u8 KEY_scan(void)
{
static u8 key_up = 0;
if(MODE_KEY==0||FUN_KEY==0)
{
delay_ms(10);

if(MODE_KEY==0)
return 1;
else if(FUN_KEY==0)
return 2;
else //补全了情况
return 3;
}
else
return 0;
}

后运行正常,也没有警告。

经过右上角男士提点:尽量少用else。程序修改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
u8 KEY_scan(void)
{
if(MODE_KEY==0||FUN_KEY==0)
{
delay_ms(100);
if(MODE_KEY==0)
return 1;
if(FUN_KEY==0)
return 2;
}
return 0;
}

也没啥问题。

2015-09-15

NRF24L01莫名其妙的又不通信了。痛心啊。还以为是硬件问题。因为软件都是复制的啊(PS:好像一直都是我找不出bug的理由^0^)
最后发现一直精简程序,想把进程都放在中断里执行。即时间片轮转算法里的时间片。

最后发现只顾着把修改发送字节却忘记了执行发送这重要的一步。

1
if (NRF24L01_TxPacket(tmp_buf) == TX_OK)

一眼看上去感觉只是一个判断发送是否完成的语句语句,但实际上发送函数也在里面。哎。脑子估计抽筋了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//启动NRF24L01发送一次数据
//txbuf:待发送数据首地址
//返回值:发送完成状况
u8 NRF24L01_TxPacket(u8 *txbuf)
{
u8 sta;
SPI2_SetSpeed(SPI_BaudRatePrescaler_4);//spi速度为9Mhz(24L01的最大SPI时钟为10Mhz)
NRF24L01_CE = 0;
NRF24L01_Write_Buf(WR_TX_PLOAD, txbuf, TX_PLOAD_WIDTH); //写数据到TX BUF 5个字节
NRF24L01_CE = 1; //启动发送
while (NRF24L01_IRQ != 0); //等待发送完成
sta = NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值
NRF24L01_Write_Reg(WRITE_REG_NRF + STATUS, sta); //清除TX_DS或MAX_RT中断标志
if (sta & MAX_TX) //达到最大重发次数
{
NRF24L01_Write_Reg(FLUSH_TX, 0xff); //清除TX FIFO寄存器
return MAX_TX;
}
if (sta & TX_OK) //发送完成
{
return TX_OK;
}
return 0xff;//其他原因发送失败
}