共2条
1/1 1 跳转至页
OS,ENTER,CRITICAL OS_ENTER_CRITICAL();的问题?
问
LPC2131中有这表例程:
uint8 UART0Getch(void)
{
uint8 err;
OS_ENTER_CRITICAL();//1处
while ((U0LSR & 0x00000001) == 0)
{ /* 没有收到数据 */
U0IER = U0IER | 0x01; /* 允许接收中断 */
OSSemPend(Uart0Sem, 0, &err); /* 等待接收数据 */2处
}
err = U0RBR; /* 读取收到的数据 */
OS_EXIT_CRITICAL();
return err;
}
void UART0_Exception(void)
{
uint8 IIR, temp, i;
OS_ENTER_CRITICAL();
while(((IIR = U0IIR) & 0x01) == 0)
{ /* 有中断未处理完 */
switch (IIR & 0x0e)
{
case 0x02: /* THRE中断 */
for (i = 0; i < UART0_FIFO_LENGTH; i++) /* 向发送FIFO填充数据 */
{
if (QueueRead(&temp, UART0SendBuf) == QUEUE_OK)
{
U0THR = temp;
}
else
{
U0IER = U0IER & (~0x02); /* 队列空,则禁止发送中断 */
}
}
break;
case 0x04: /* 接收数据可用 */
OSSemPost(Uart0Sem); /* 通知接收任务 */3处
U0IER = U0IER & (~0x01); /* 禁止接收及字符超时中断 */
break;
case 0x06: /* 接收线状态 */
temp = U0LSR;
break;
case 0x0c: /* 字符超时指示 */
OSSemPost(Uart0Sem); /* 通知接收任务 */
U0IER = U0IER & (~0x01); /* 禁止接收及字符超时中断 */
break;
default :
break;
}
}
VICVectAddr = 0; // 通知中断控制器中断结束
OS_EXIT_CRITICAL();
}
在1处有关中断
OS_ENTER_CRITICAL();
在2处又挂起等待中断发信息,中断都 关了还能等中断3处发信息???
不知所以???
OS_ENTER_CRITICAL();是这样定义的:
case 0x02: /* 关中断函数OS_ENTER_CRITICAL(),参考os_cpu.h文件 */
__asm
{
MRS R0, SPSR
ORR R0, R0, #NoInt
MSR SPSR_c, R0
}
OsEnterSum++;
break;
答 1: 2处,上面一条不是允许接收中断么? 答 2: 用仿真器调试能下来吗? 答 3: re这个问题以前大家讨论过,周工也给了详细解答。请你找来看看。 答 4: 看了以前的贴子,还是有问题john1225cn兄:
看了以前你发的贴子,有关于此的讨论,但是最后我还没有看懂,最后一位高手如此回答:
“
调用函数OSSemPend()后,进行任务调度,进入别的任务中,总有一个任务的中断是开着的。所以就可以进入中断服务程序了。”
什么是总有一个任务是开着的,开中断不是可以用OS_EXIT_CRITICAL()完成吗?
OS_ENTER_CRITICAL()
与
OS_EXIT_CRITICAL()
实现的目的就是不让中间的任务进入其他的中断,如果又进入其他的中断任务实现OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()的目的又是什么????
请john1225cn兄帮忙回答一下! 答 5: re每个任务有自己的状态寄存器。
在任务中调用关中断,就是关闭本任务的中断,在本任务执行的时候不准中断。
但是当其他任务执行时,还是可以发生中断。 答 6: john1225cn兄:状态寄存器应该只有一个吧?john1225cn兄:
状态寄存器数量是1个,但是所有工作模式共享CPSR,其他的SPSR只是在工作模式切换时保存CPSR;所以我的理解是如果所有的任务在用户模式则状态寄存器只有一个CPSR;
因在ZLG的开发板中实现OS_ENTER_CRITICAL() 是通过SWI软中断完成 的,所以在OS_ENTER_CRITICAL() 中只修改了SPSR,软中断返回后还给SPSR,如以下:
OS_ENTER_CRITICAL();是这样定义的:
case 0x02: /* 关中断函数OS_ENTER_CRITICAL(),参考os_cpu.h文件 */
__asm
{
MRS R0, SPSR
ORR R0, R0, #NoInt
MSR SPSR_c, R0
}
OsEnterSum++;
break;
另外如下的代码:
uint8 UART0Getch(void)
{
uint8 err;
OS_ENTER_CRITICAL();//1处
while ((U0LSR & 0x00000001) == 0)
{ /* 没有收到数据 */
U0IER = U0IER | 0x01; /* 允许接收中断 */2处
OSSemPend(Uart0Sem, 0, &err); /* 等待接收数据 */
}
err = U0RBR; /* 读取收到的数据 */
OS_EXIT_CRITICAL();
return err;
}
在1处是关IRQ中断,在2外只是开了串口中断,那么此时IRQ中断是关闭的,开中断还有什么意义?
如果按照john1225cn兄所说的在任务中有单独状态寄存器,那么以上应为同一任务,关了中断,在此任务中应该也不会响应中断,那就有可能OSSemPend(Uart0Sem, 0, &err)永远挂着???
不知理解那里出错了???
郁闷中!
答 7: 请zlg315,john1225cn兄 麻烦回答一下!!!以上问题是否是普遍的问题,麻烦回答一下
答 8: cloudlily可以这样理解:
串口任务挂了。中断也关了,串口中断开了。串口任务挂了,
然后,另外一个任务task1运行了。task1开始运行的时候,操作系统会全部更新寄存器为task1里原来的状态,包括状态寄存器。在task1运行的时候,状态寄存器则是允许中断的。
因此,就发生了串口中断。 答 9: 谢谢 john1225cn 兄非常谢谢 john1225cn 兄不厌其烦的解答!
对于中断在其他任务中可以得到响应我已理解了,但是对于以下的代码,
OS_ENTER_CRITICAL()和 OS_EXIT_CRITICAL()是否可以去掉,本来关中断和开中断是为了保护临界代码,现在中间 OSSemPend(Uart0Sem, 0, &err)已挂到其他的任务中,好像开中断和关中断没有什么意义了!
uint8 UART0Getch(void)
{
uint8 err;
OS_ENTER_CRITICAL();//1处
while ((U0LSR & 0x00000001) == 0)
{ /* 没有收到数据 */
U0IER = U0IER | 0x01; /* 允许接收中断 */
OSSemPend(Uart0Sem, 0, &err); /* 等待接收数据 */2处
}
err = U0RBR; /* 读取收到的数据 */
OS_EXIT_CRITICAL();
return err;
}
答 10: 这个问题我查了以前的讨这个问题我查了以前的讨论,好像没有一个真正的结果,不知是否ZLG的模块代码有问题?
请高手指点! 答 11: 1存在对模块寄存器的读写,而且读写内容会对结果发生改变,所以禁止中断,意图是保证接受数据的流程只能是:1.读取线状态,如果没有数据进来,则任务挂起,等待信号量 2.如果已经有数据进来在getch之前,则直接读数据。
中断的意图只是保证函数只能按照这两种意图发生,因为实时系统,确定程序以已知的行为发生动作是很重要的,不能存在不确定性。
但是不可否认,接口函数写的比较蹩脚,要知道,它挂起的不是函数,而是调用这个函数的任务;清晰的设计任务不会产生问题,可是很多初学者都在一个任务里面顺序做很多事情,然后心血来潮写个别的任务,操作系统多任务还是强调任务之间耦合关系的。
这个函数最简单的改法就是把信号量取改为限时:OSSemPend(Uart0Sem, 0, &err); 0改为确定时间。
这样可以防止多种中断通知事件的时候,不良的任务分配带来错误运行。
当然,大家也可以自己写串口接收函数,简单而且高效,毕竟不同的项目是不同的用法,通用函数当然不可能最优。
uint8 UART0Getch(void)
{
uint8 err;
OS_ENTER_CRITICAL();//1处
while ((U0LSR & 0x00000001) == 0)
{ /* 没有收到数据 */
U0IER = U0IER | 0x01; /* 允许接收中断 */
OSSemPend(Uart0Sem, 0, &err); /* 等待接收数据 */2处
}
err = U0RBR; /* 读取收到的数据 */
OS_EXIT_CRITICAL();
return err;
}
void UART0_Exception(void)
{
uint8 IIR, temp, i;
OS_ENTER_CRITICAL();
while(((IIR = U0IIR) & 0x01) == 0)
{ /* 有中断未处理完 */
switch (IIR & 0x0e)
{
case 0x02: /* THRE中断 */
for (i = 0; i < UART0_FIFO_LENGTH; i++) /* 向发送FIFO填充数据 */
{
if (QueueRead(&temp, UART0SendBuf) == QUEUE_OK)
{
U0THR = temp;
}
else
{
U0IER = U0IER & (~0x02); /* 队列空,则禁止发送中断 */
}
}
break;
case 0x04: /* 接收数据可用 */
OSSemPost(Uart0Sem); /* 通知接收任务 */3处
U0IER = U0IER & (~0x01); /* 禁止接收及字符超时中断 */
break;
case 0x06: /* 接收线状态 */
temp = U0LSR;
break;
case 0x0c: /* 字符超时指示 */
OSSemPost(Uart0Sem); /* 通知接收任务 */
U0IER = U0IER & (~0x01); /* 禁止接收及字符超时中断 */
break;
default :
break;
}
}
VICVectAddr = 0; // 通知中断控制器中断结束
OS_EXIT_CRITICAL();
}
在1处有关中断
OS_ENTER_CRITICAL();
在2处又挂起等待中断发信息,中断都 关了还能等中断3处发信息???
不知所以???
OS_ENTER_CRITICAL();是这样定义的:
case 0x02: /* 关中断函数OS_ENTER_CRITICAL(),参考os_cpu.h文件 */
__asm
{
MRS R0, SPSR
ORR R0, R0, #NoInt
MSR SPSR_c, R0
}
OsEnterSum++;
break;
答 1: 2处,上面一条不是允许接收中断么? 答 2: 用仿真器调试能下来吗? 答 3: re这个问题以前大家讨论过,周工也给了详细解答。请你找来看看。 答 4: 看了以前的贴子,还是有问题john1225cn兄:
看了以前你发的贴子,有关于此的讨论,但是最后我还没有看懂,最后一位高手如此回答:
“
调用函数OSSemPend()后,进行任务调度,进入别的任务中,总有一个任务的中断是开着的。所以就可以进入中断服务程序了。”
什么是总有一个任务是开着的,开中断不是可以用OS_EXIT_CRITICAL()完成吗?
OS_ENTER_CRITICAL()
与
OS_EXIT_CRITICAL()
实现的目的就是不让中间的任务进入其他的中断,如果又进入其他的中断任务实现OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()的目的又是什么????
请john1225cn兄帮忙回答一下! 答 5: re每个任务有自己的状态寄存器。
在任务中调用关中断,就是关闭本任务的中断,在本任务执行的时候不准中断。
但是当其他任务执行时,还是可以发生中断。 答 6: john1225cn兄:状态寄存器应该只有一个吧?john1225cn兄:
状态寄存器数量是1个,但是所有工作模式共享CPSR,其他的SPSR只是在工作模式切换时保存CPSR;所以我的理解是如果所有的任务在用户模式则状态寄存器只有一个CPSR;
因在ZLG的开发板中实现OS_ENTER_CRITICAL() 是通过SWI软中断完成 的,所以在OS_ENTER_CRITICAL() 中只修改了SPSR,软中断返回后还给SPSR,如以下:
OS_ENTER_CRITICAL();是这样定义的:
case 0x02: /* 关中断函数OS_ENTER_CRITICAL(),参考os_cpu.h文件 */
__asm
{
MRS R0, SPSR
ORR R0, R0, #NoInt
MSR SPSR_c, R0
}
OsEnterSum++;
break;
另外如下的代码:
uint8 UART0Getch(void)
{
uint8 err;
OS_ENTER_CRITICAL();//1处
while ((U0LSR & 0x00000001) == 0)
{ /* 没有收到数据 */
U0IER = U0IER | 0x01; /* 允许接收中断 */2处
OSSemPend(Uart0Sem, 0, &err); /* 等待接收数据 */
}
err = U0RBR; /* 读取收到的数据 */
OS_EXIT_CRITICAL();
return err;
}
在1处是关IRQ中断,在2外只是开了串口中断,那么此时IRQ中断是关闭的,开中断还有什么意义?
如果按照john1225cn兄所说的在任务中有单独状态寄存器,那么以上应为同一任务,关了中断,在此任务中应该也不会响应中断,那就有可能OSSemPend(Uart0Sem, 0, &err)永远挂着???
不知理解那里出错了???
郁闷中!
答 7: 请zlg315,john1225cn兄 麻烦回答一下!!!以上问题是否是普遍的问题,麻烦回答一下
答 8: cloudlily可以这样理解:
串口任务挂了。中断也关了,串口中断开了。串口任务挂了,
然后,另外一个任务task1运行了。task1开始运行的时候,操作系统会全部更新寄存器为task1里原来的状态,包括状态寄存器。在task1运行的时候,状态寄存器则是允许中断的。
因此,就发生了串口中断。 答 9: 谢谢 john1225cn 兄非常谢谢 john1225cn 兄不厌其烦的解答!
对于中断在其他任务中可以得到响应我已理解了,但是对于以下的代码,
OS_ENTER_CRITICAL()和 OS_EXIT_CRITICAL()是否可以去掉,本来关中断和开中断是为了保护临界代码,现在中间 OSSemPend(Uart0Sem, 0, &err)已挂到其他的任务中,好像开中断和关中断没有什么意义了!
uint8 UART0Getch(void)
{
uint8 err;
OS_ENTER_CRITICAL();//1处
while ((U0LSR & 0x00000001) == 0)
{ /* 没有收到数据 */
U0IER = U0IER | 0x01; /* 允许接收中断 */
OSSemPend(Uart0Sem, 0, &err); /* 等待接收数据 */2处
}
err = U0RBR; /* 读取收到的数据 */
OS_EXIT_CRITICAL();
return err;
}
答 10: 这个问题我查了以前的讨这个问题我查了以前的讨论,好像没有一个真正的结果,不知是否ZLG的模块代码有问题?
请高手指点! 答 11: 1存在对模块寄存器的读写,而且读写内容会对结果发生改变,所以禁止中断,意图是保证接受数据的流程只能是:1.读取线状态,如果没有数据进来,则任务挂起,等待信号量 2.如果已经有数据进来在getch之前,则直接读数据。
中断的意图只是保证函数只能按照这两种意图发生,因为实时系统,确定程序以已知的行为发生动作是很重要的,不能存在不确定性。
但是不可否认,接口函数写的比较蹩脚,要知道,它挂起的不是函数,而是调用这个函数的任务;清晰的设计任务不会产生问题,可是很多初学者都在一个任务里面顺序做很多事情,然后心血来潮写个别的任务,操作系统多任务还是强调任务之间耦合关系的。
这个函数最简单的改法就是把信号量取改为限时:OSSemPend(Uart0Sem, 0, &err); 0改为确定时间。
这样可以防止多种中断通知事件的时候,不良的任务分配带来错误运行。
当然,大家也可以自己写串口接收函数,简单而且高效,毕竟不同的项目是不同的用法,通用函数当然不可能最优。
共2条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |