Beep(1950, 20); n++;
for(i=0;i<2000;i++) { //通过空循环进行延时 for(j=0;j<50000;j++); }
OSTimeDly(OS_TICKS_PER_SEC*5); } }
void YourTask(void *pdata) {
while(1) {
printf(\ Beep(4000, 20); m++;
for(i=0;i<3000;i++) { //通过空循环进行延时 for(j=0;j<50000;j++); }
if(m>=3) {
printf(\取消任务MyTask的延时!\\n\ m = 0;
OSTimeDlyResume(5); } } }
3、任务之间的单向同步(通过信号量):按键控制音频播放(PC)、按键控制LED(Proteus) 设计两个任务,第一个任务是按键检测任务(TaskKey),第二个任务是串口发送任务(TaskSendByUART),这两个任务要求通过信号量进行同步,即按键任务检测到按键后,串口发送任务将按键次数信息发送到串口终端上。注意:要求创建串口发送任务时能够通过任务函数的参数pdata实现波特率的设置。
检测到按键后,串口发送按键次数信息,8个Led再以二进制数的形式显示按键次数。如何改造程序达到以上要求的实验效果,请画出通过信号量实现三个任务同步的示意图。
void TaskLed(void *pdata) { while(1) {
OSTaskSuspend(OS_PRIO_SELF); n = (n+1) % 255; IO1SET = LEDCON; IO1CLR = n<<16; } }
void TaskKey(void *pdata) {
while(1) { if((IO0PIN & KEYCON) == 0)//检测到按键按下 { OSTimeDly(OS_TICKS_PER_SEC/50); //消抖 if((IO0PIN & KEYCON) == 0)//确认按键按下 { while((IO0PIN & KEYCON) == 0);//等待按键释放 OSTaskResume(5); } } } }
4、任务之间的双向同步(通过两个信号量):上课示例
void MyTask(void *pdata)
{
while(1) {
OSSemPend(sem1,0,&err); if(err == OS_NO_ERR) {
printf(\任务MyTask:我制造快乐!\\n\ Beep(1950, 20);
for(i=0;i<3000;i++) { for(j=0;j<50000;j++); } }
OSTimeDly(OS_TICKS_PER_SEC/10); OSSemPost(sem2); } }
void YourTask(void *pdata) {
while(1) {
OSSemPend(sem2,0,&err); if(err == OS_NO_ERR) {
printf(\任务YourTask: 我消费快乐!\\n\
for(i=0;i<=14;i++) Beep(music_book[i], 20); }
OSTimeDly(OS_TICKS_PER_SEC*2); OSSemPost(sem1); } }
5、多个任务之间的同步:上课示例、实验七 实验七:
编写三个任务,一个任务负责图形按钮点击检测,一个任务负责音频播放(如生日快乐、两只老虎等),一个任务负责通过进度条显示音频播放进度,要求通过信号量或消息邮箱实现任务之间的同步和通信。
void MyTask(void * pdata) { while(1) {
while (GUI_WaitKey() != GUI_ID_OK); OSSemPost(beepsem); } }
void YourTask(void * pdata) { while(1) { OSSemPend(beepsem,0,&err); for (i=0;i<32;i++) { Beep(FREQUENCY[i],DELAY[i]); OSSemPost(progsem); } } }
void HerTask(void * pdata) { while(1) { for (i=0;i<32;i++) { OSSemPend(progsem,0,&err); //改变进程条的进度 PROGBAR_SetValue(hProgBar,i); WM_Exec(); } } }
6、多个任务同步一个任务(事件标识组):上课示例
void MyTask(void *pdata) {
while(1) {
printf(\任务MyTask:等我来按键!\\n\ ch = getch();
if(ch==13) OSFlagPost(FLAGW,0x01,OS_FLAG_SET,&err); } }
void YourTask(void *pdata) {
while(1) {
printf(\任务YourTask:等你来说话!\\n\
OSFlagPost(FLAGW,0x02,OS_FLAG_SET,&err); OSTimeDly(OS_TICKS_PER_SEC*3); } }
void HisTask(void *pdata) {
while(1) {
OSFlagPend(FLAGW,0x03,OS_FLAG_WAIT_SET_ALL+OS_FLAG_CONSUME,0,&err); if(err == OS_NO_ERR) {
printf(\任务HisTask: 万事具备,该他来唱首歌啦!\\n\ for(i=0;i<=14;i++) Beep(music_book[i], 20); } } }
7、一个任务同步多个任务(消息广播、多个信号量):上课示例、实验二
实验二:检测到按键后,串口发送按键次数信息,8个Led再以二进制数的形式显示按键次数。如何改造程序达到以上要求的实验效果,请画出通过信号量实现三个任务同步的示意图。
TaskKey 键盘任务
void TaskKey(void *pdata) { INT16U i;
pdata = pdata; while(1) {
for(i=0;i<1000;i++); //延时,去毛刺
if( (IO0PIN&KEY)!=0 ) continue;//未按键,继续等待延时 OSSemPost(sem1);//发送一个信号量函数; while((IO0PIN & KEY) == 0) { //按键未释放 IO0SET = KEY; } } }
TasSendByUart 串口发送任务(低优先级) void TaskSendByUart(void *pdata) {
INT16U Baud,times=0; INT8U err; char s[30];
pdata = pdata;
Baud = *(INT16U*) pdata; //baud用来设置波特率; UART0_Init(Baud);
UART0SendStr(SendString); while(1) {
OSSemPend(sem1,0,&err);//等待一个信号量函数; times++;
sprintf(s,\ UART0SendStr(s);
OSSemPost(sem2); //发送一个信号量函数; } }
TaskLed Led控制任务
void TaskLed(void *pdata) { INT8U err;
pdata = pdata; /* 避免编译警告 */ IO0DIR |= LEDCON; / 设置LED输出 IO0SET = LEDCON; while(1) {
OSSemPend(sem2,0,&err); //等待一个信号量函数; led++;
IO0SET = LEDCON;
IO0CLR =(led<<8); } }
8、共享资源的互斥访问:信号量、互斥型信号量(上课示例、实验三) 实验三:
1、以下为两个串口发送任务,第一个串口发送任务将字符串”I am Task A!”发送到串口终端,第二个串口发送任务将字符串”I am Task B!”发送到串口终端,请问输出结果有什么问题?为什么会出现该问题?如何通过信号量或互斥型信号量解决上述问题。画出两个任务对串口终端实现互斥访问的示意图,并改造上述程序。
OS_EVENT *mutex;
mutex = OSMutexCreate(2,&err); void TaskA(void *pdata) { INT16U Baud,i=0; INT8U err; pdata = pdata;
Baud = *(INT16U*) pdata; UART0_Init(Baud); while(1) {
OSMutexPend(mutex,0,&err);//申请互斥型信号量(互斥型信号量指针、等待时限、错误信息); i = 0;
while(StrA[i]!='\\0') {
UART0SendByte(StrA[i]); // 发送数据 i++;
OSTimeDly(10); }
OSMutexPost(mutex); } }
void TaskB(void *pdata) { INT16U i=0; INT8U err; pdata = pdata; while(1) {
OSMutexPend(mutex,0,&err); i = 0;
while(StrB[i]!='\\0') {
UART0SendByte(StrB[i]); // 发送数据 i++;
OSTimeDly(20); }
OSMutexPost(mutex); } }
9、任务之间的数据通信(上课示例、实验四、实验七) 实验四:
(1) 建立两个μC/OS-II任务,第一个键盘扫描任务(TaskKeyScan)作为数据发送任务,第二个是串口发送任务(TaskUartSend),按键扫描任务负责对按键进行检测,检测到按键后,将按键的行、列号扫描码作为消息发送到消息邮箱。串口发送任务等待消息邮箱的消息(按键的行列号),获得消息后将相关信息发送到串口终端。
void TaskSendByUart(void *pdata) {
INT16U Baud,times=0; INT8U err; _key *pkey; char s[30]; pdata = pdata;
Baud = *(INT16U*) pdata; UART0_Init(Baud); while(1) {
pkey = (_key *)OSMboxPend(mbox,0,&err);
sprintf(s,\ UART0SendStr(s); } }
void TaskKeyScan(void *pdata) { while(1) {
while((IO1PIN&(0xf0<<16)) != (0xf0<<16)); //等待按键释放