引用 金星凌日:这种编程算法一开始就是错的……如果目的资源是唯一性的,这种算法在ucos、windows、linux上都解决不了。
我说的就是单线程的情况,与多线程根本没有关系。
举个例子,某块跑ucos的板子上只有一个串口,任务A需要把100KB数据实时、完整的从串口发出,所以它直接直接调用putchar()一类的函数逐个字节发送;恰好发到一半时,任务B也要从串口实时、完整的发送200KB数据出去……二虎相争必有一伤。这是任何OS都解决不了的。
所以各种OS、协议栈到处都充斥着各种各样的队列
Otherint main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
SysTick_Configuration();
OSInit();
OSTaskCreate( TaskStart, //task pointer
(void *)0, //parameter
(OS_STK *)&TASK_START_STK[START_STK_SIZE-1], //task stack top pointer
START_TASK_Prio ); //task priority
OSStart();
return 0;
}
//开始任务
void TaskStart(void * pdata)
{
pdata = pdata;
OS_ENTER_CRITICAL();
OSTaskCreate(TaskLed, (void * )0, (OS_STK *)&TASK_LED_STK[LED_STK_SIZE-1], LED_TASK_Prio);
OSTaskCreate(TaskLed1, (void * )0, (OS_STK *)&TASK_LED1_STK[LED1_STK_SIZE-1], LED1_TASK_Prio);
OSTaskSuspend(START_TASK_Prio); //suspend but not delete
OS_EXIT_CRITICAL();
}
//任务1
//控制DS0的亮灭.
void TaskLed(void *pdata)
{
while(1)
{
LED0 = !LED0;
OSTimeDlyHMSM(0,0,1,100);
}
}
//任务2
//控制DS1的亮灭.
void TaskLed1(void *pdata)
{
while(1)
{
LED1 = !LED1;
OSTimeDlyHMSM(0,0,1,300);
}
}
OtherTIM3_IRQHandler PROC
PUSH {r4,lr}
MRS r4,MSP
MOV r0,r4
ADD r0,r0,#8
MOV r4,r0
LDR r0,|L0.640|
STR r4,[r0,#0]
BL IRQHandler
POP {r4,pc}
ENDP
----->生成汇编文件后可以看到,进入TIM3_IRQHandler函数先把R4和LR压栈(这是编译器自动做的),MSP堆栈指针 - 8 ----->MRS r4,MSP 保存栈指针 ----->指针+8(对前面R4和LR的补偿)对准 8个被自动压栈的寄存器的R0 ----->保存指针到全局变量Address_BASE ----->bl IRQHandler 调用任务调度程序 ----->清除中断待处理位 ----->根据之前保存的栈地址,加载8个寄存器保存当前任务现场 -----> 调用任务二的地址-----> task->Start_Next(); 更新任务标志-----> 退出中断 并 恢复被修改了返回地址的8个寄存器 -----> 执行任务1-----> 定时器中断时间到 ---->进入中断 -----> 保存任务1现场-----> 恢复任务0 ----->退出中断 ----->goto 标志;
Other#include "../h/main.h"
extern Task *task;
int main(void)
{
task = new Task(); //创建任务管理对象 这是一个C++类对象
Init();//初始化 时钟 串口 GPIO
Timerx_Init(20,7199);//初始化TIM3,开中断,每2ms进一次中断
TIM3->CNT = 0x01;//意义不明 不要也行
__asm //內联汇编
{
bl Task0 //跳转到任务1
}
// while (true);
// delete task;
}
int temp = 0;
void Task0(void) //任务1
{
while (true)
{
LED0 = !LED0;
}
}
void Task1(void) //任务2
{
while (true)
{
LED1 = !LED1;
}
}
Otherclass Task //任务管理类
{
public:Task(void) //构造函数,初始化时会自动调用
{
Reg_Buff[0][6]=((unsigned int)&Task0) ; //初始化任务0的指针
Reg_Buff[1][6]=((unsigned int)&Task1) ; //初始化任务1的指针
Reg_Buff[0][6]=Reg_Buff[1][7]=0x61000000 ; //初始化xRSP
Current = 0;
Next = 1;
}
public: static const unsigned char Count = Task_Count;
public: unsigned char Current; //当前任务
public: unsigned char Next ; //下一个任务
public: volatile unsigned int Reg_Buff[Task_Count][8];
public: void Start_Next() //更新至下一个任务
{
(Current + 1 < Count) ? Current++ : Current = 0;
(Next + 1 < Count) ? Next++ : Next = 0;
// if (Next != 0 && (Next - Current) != 1)
// {
// while (true)
// {
// }
// }
}
};
OtherTask *task ;
unsigned int Address_BASE = 0;
void IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx的中断待处理位:TIM 中断源
__asm
{
ldr r5, [Address_BASE]
str r5, [&task->Reg_Buff[task->Current][0]]//R0
ldr r5, [Address_BASE , 0x4]
str r5, [&task->Reg_Buff[task->Current][1]]//R1
ldr r5, [Address_BASE , 0x8]
str r5, [&task->Reg_Buff[task->Current][2]]//R2
ldr r5, [Address_BASE , 0xc]
str r5, [&task->Reg_Buff[task->Current][3]]//R3
ldr r5, [Address_BASE , 0x10]
str r5, [&task->Reg_Buff[task->Current][4]]//R12
// ldr r5, [Address_BASE , 0x14]
// str r5, [&task->Reg_Buff[task->Current][5]]//R13 LR
ldr r5, [Address_BASE , 0x18]
str r5, [&task->Reg_Buff[task->Current][6]]//R14 PC
ldr r5, [Address_BASE , 0x1c]
str r5, [&task->Reg_Buff[task->Current][7]]//R15 xRSP
/*↑↑↑保存当然运行中的任务现场↑↑↑*/
ldr r5, [&task->Reg_Buff[task->Next][0]]//R0
str r5, [Address_BASE]
ldr r5, [&task->Reg_Buff[task->Next][1]]//R1
str r5, [Address_BASE, 0x4]
ldr r5, [&task->Reg_Buff[task->Next][2]]//R2
str r5, [Address_BASE, 0x8]
ldr r5, [&task->Reg_Buff[task->Next][3]]//R3
str r5, [Address_BASE, 0xc]
ldr r5, [&task->Reg_Buff[task->Next][4]]//R12
str r5, [Address_BASE, 0x10]
// ldr r5, [&task->Reg_Buff[task->Next][5]]//R13 LR
// str r5, [Address_BASE, 0x14]
ldr r5, [&task->Reg_Buff[task->Next][6]]//R14 PC
//orr r5, 0x01
str r5, [Address_BASE, 0x18]
ldr r5, [&task->Reg_Buff[task->Next][7]]//R15 xRSP
str r5, [Address_BASE, 0x1c]
/*↑↑↑恢复上一个任务的现场↑↑↑*/
}
task->Start_Next(); //下一个任务
}
}
extern "C"
{
void TIM3_IRQHandler(void) //TIM3中断 中断中不能有太多东西,否则进中断时压栈太多 MSP不容易计算
{
__ASM
{
mrs r4, msp
add r4, 0x08
str r4, [&Address_BASE]
bl IRQHandler
}
}
}
[修改于 10年0个月前 - 2015/06/05 14:26:47]
引用 金星凌日:这种编程算法一开始就是错的……如果目的资源是唯一性的,这种算法在ucos、windows、linux上都解决不了。
我说的就是单线程的情况,与多线程根本没有关系。
引用 amo:我说的那种情况也与惟一性资源没有任何关系。
这种编程算法一开始就是错的……如果目的资源是唯一性的,这种算法在ucos、windows、linux上都解决不了。
举个例子,某块跑ucos的板子上只有一个串口,任务A需要把100KB数据实时、完整的从串口发出,所以它直接直接调用putch...
引用 金星凌日:规则不能这么随便滥用……
我说的那种情况也与惟一性资源没有任何关系。
此外,就算这种写法完全错误,也没法阻止有人这样写,特别是ABCD由不同的人写的情况下。
我的意思实际上与《Effective C++》中的这条规则类似:使接口不易被误用。
引用 amo:这些我都知道,可能是我没有表达清楚。
初学者编程,往往喜欢一个函数直接执行完所有功能;稍进阶后就是层层调用各种函数直到完成所有功能……不要说别人接手,就是自己过一段时间再看都会两眼茫然
初看成熟的开源代码,一般会很不适应,比如发送一个数据包,只是简单复制到一个数组或队列……然...
引用 金星凌日:这种问题目前可能没有什么好办法解决,只能强调编程规范和单元测试……
这些我都知道,可能是我没有表达清楚。
我的意思是,使用了这种协程,这个函数就会变成不可复制的资源。而C语言中没有办法阻止这种错误用法,除非人工检查。或许使用断言会有一定帮助,但这并不能解决所有问题。
引用 uestc008@163.com:我写了两年C# 汇编已经看不懂了。。。。。
哦,我的汇编部分已经编译没错误了,可以保存现场和恢复现场,就是任务切换还不太清楚怎么弄的。楼主用的编译器和我的不一样,所以部分不一样。楼主两句话要完成的,我要写好多,
__ASM vo……
引用 张静茹:哦,没事,切换我也是靠的定时器,就是保存完现场后再回去是不是需要什么。
我写了两年C# 汇编已经看不懂了。。。。。
切换任务靠的是定时器
200字以内,仅用于支线交流,主线讨论请采用回复功能。