求嵌入式开发板代码解读(要求:对代码整体结构及每行代码进行注释).一旦选中,可支付宝支付100元人民币。多谢。

C语言 码拜 6年前 (2015-05-11) 278次浏览 0个评论
 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ioctl.h>

#include “debug.h”
#include “serial.h”
#include “gprs.h”

/* 按键的设备文件路径,不能修改 */
#define BTNS_DEV_PATH “/dev/buttons”
/* LED的设备文件路径,不能修改 */
#define LEDS_DEV_PATH “/dev/leds”
/* 蜂鸣器的设备文件路径,不能修改 */
#define PWM_DEV_PATH “/dev/pwm”
/* GPRS的设备文件路径,根据实际情况修改 */
#define GPRS_DEV_PATH “/dev/ttyUSB0”

/* 设置蜂鸣器频率的命令,不能修改 */
#define PWM_IOCTL_SET_FREQ 1
/* 停止蜂鸣器的命令,不能修改 */
#define PWM_IOCTL_STOP 0

/* 保存线程ID的结构体 */
struct thread_info {
pthread_t id;
};

/* 定义三个结构体变量,实际上只用了2个 */
static struct thread_info tinfo[3] = {{0}};

/* 按键的文件描述符 */
int btn_fd;
/* LED的文件描述符 */
int led_fd;
/* 蜂鸣器的文件描述符 */
int pwm_fd;
/* 电话号码字符串指针 */
char *phonenum;
/* 短信收发的互斥标志
 * busy = 0,可以接收短信,不能发送短信
 * busy = 1, 准备发送短信,但还不能发送短信,只有等接收短信的线程确认后,即busy = 2时才能真正开始发送短信
 * busy = 2, 只能发送短信,不能接收短信 */
int busy = 0;

void *thread_main(void *arg)
{
int i;
int ret;
char buttons[6] = {“”0″”, “”0″”, “”0″”, “”0″”, “”0″”, “”0″”};
char current_buttons[6];

while (1) {
/* 读取按键的值,总共6个按键,按键按下返回字符1,否则返回字符0 */
ret = read(btn_fd, current_buttons, sizeof(current_buttons));
/* 如果读取的个数不为6,则说明读按键失败,打印错误信息后,线程退出 */
if (ret != sizeof(current_buttons)) {
printf(“Get buttuns status failed\n”);
exit(1);
}

/* 循环6次,判断哪个按键被按下了 */
for (i = 0; i < sizeof(buttons) / sizeof(buttons[0]); i++) {
/* 如果这次读到的按键值和上次的按键值不一致(该算法确保按下一次按键只发送一次短信) */
if (buttons[i] != current_buttons[i]) {
/* 那么将刚获得到的按键值进行更新 */
buttons[i] = current_buttons[i];
/* 如果按键按下 */
if (current_buttons[i] == “”1″”) {
/* 设置标志,表示准备要发送短信 */
busy = 1;
/* 等待另外一个线程确认后,才能开始发送短信 */
while (busy != 2);
/* 根据按下的不同按键,发送不同的短信 */
switch (i) {
case 0:
/* 调用短信发送函数,给指定的电话号码发送短信 */
gprs_send_msg(phonenum, “K1 pressed down\n”);
break;
case 1:
gprs_send_msg(phonenum, “K2 pressed down\n”);
break;
case 2:
gprs_send_msg(phonenum, “K3 pressed down\n”);
break;
case 3:
gprs_send_msg(phonenum, “K4 pressed down\n”);
break;
case 4:
gprs_send_msg(phonenum, “K5 pressed down\n”);
break;
case 5:
gprs_send_msg(phonenum, “K6 pressed down\n”);
break;
}
/* 短信发送完成后,通知另外一个线程可以继续接收短信 */
busy = 0;
/* 延时200mS,进行按键消抖 */
usleep(200000);
}
}
}
}
/* 如果异常发生,线程退出 */
pthread_exit(NULL);
}

void *thread_gprs(void *arg)
{
int i;
int ret;
char msg[256];
unsigned int nums;
unsigned int msgs[32];

/* 删除所有的短信,避免SIM卡满了后,不能接收短信 */
ret = gprs_del_all_msg();
if (ret) {
printf(“Delete all message failed\n”);
pthread_exit(NULL);
}

while (1) {
/* 如果busy不为0,则说明不能接收短信 */
if (busy != 0) {
/* 如果busy = 1,则说明有线程准备要开始发送短信 */
if (busy == 1)
/* 通知另外一个线程,可以开始发送短信 */
busy = 2;
continue;
}
/* 尝试读取短信,msgs数组中保存了所有读到短信的索引号 */
ret = gprs_recv_msg(msgs, &nums);
/* 如果有新短信 */
if (ret > 0) {
/* 则读出所有的新短信,一般一次只有一条 */
for (i = 0; i < nums; i++) {
/* 清0保存返回短信内容的缓存 */
memset(msg, 0, sizeof(msg));
/* 读取指定索引号的短信 */
ret = gprs_read_msg(msgs[i], msg);
/* 将刚读到的短信删除,避免短信太多,SIM卡被占满 */
if (gprs_del_msg(msgs[i]) != 0)   
printf(“Delete message %d failed\n”, i);

if (ret < 0) {                    
printf(“Read message %d failed\n”, i);
continue;         
}

/* 根据短信的内容进行相应的控制 */
/* 打开LED */
if (strcmp(msg, “turn on LED1”) == 0) {
/* 控制LED亮的操作,1表示点亮,0表示是LED1 */
ioctl(led_fd, 1, 0);
printf(“Turn on LED1 on the board\n”);
}
if (strcmp(msg, “turn on LED2”) == 0) {
/* 控制LED亮的操作,1表示点亮,1表示是LED2 */
ioctl(led_fd, 1, 1);
printf(“Turn on LED2 on the board\n”);
}
if (strcmp(msg, “turn on LED3”) == 0) {
/* 控制LED亮的操作,1表示点亮,2表示是LED3 */
ioctl(led_fd, 1, 2);
printf(“Turn on LED3 on the board\n”);
}
if (strcmp(msg, “turn on LED4”) == 0) {
/* 控制LED亮的操作,1表示点亮,3表示是LED4 */
ioctl(led_fd, 1, 3);
printf(“Turn on LED4 on the board\n”);
}

/* 关闭LED */
if (strcmp(msg, “turn off LED1”) == 0) {
/* 控制LED亮的操作,0表示熄灭,0表示是LED1 */
ioctl(led_fd, 0, 0);
printf(“Turn on LED1 on the board\n”);
}
if (strcmp(msg, “turn off LED2”) == 0) {
ioctl(led_fd, 0, 1);
printf(“Turn on LED2 on the board\n”);
}
if (strcmp(msg, “turn off LED3”) == 0) {
ioctl(led_fd, 0, 2);
printf(“Turn on LED3 on the board\n”);
}
if (strcmp(msg, “turn off LED4”) == 0) {
ioctl(led_fd, 0, 3);
printf(“Turn on LED4 on the board\n”);
}

/* 报警 */
if (strcmp(msg, “alarm”) == 0) {
printf(“Turn on PWM on the board\n”);
/* 打开蜂蜜器设备文件 */
pwm_fd = open(PWM_DEV_PATH, O_RDONLY);
if (btn_fd == -1) {
perror(“Buzzer”);
exit(1);
}
/* 设置蜂鸣器的频率为500Hz */
ioctl(pwm_fd, PWM_IOCTL_SET_FREQ, 500);
/* 联系响3秒 */
sleep(3);
/* 停止蜂鸣器鸣叫 */
ioctl(pwm_fd, PWM_IOCTL_STOP);
/* 关闭蜂鸣器设备文件 */
close(pwm_fd);
}
}
}
}
/* 如果异常发生,线程退出 */
pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
int ret;

/* 判断参数的个数是否等于2,运行该程序需要执行“./gprsctl xxxxxxxxxxx”命令,
 * 其中./gprsctl是参数1,后面的xxxxxxxxxxx是要接收短信的手机电话号码,如果
 * 参数个数不正确,则打印使用的提示信息,并退出程序。
 */
if (argc != 2) {
printf(“Please enter the phone number\n”);
printf(“Usage: %s [phone number]\n”, argv[0]);
exit(1);
}
/* 判断电话号码的长度是否为11位,如果不是则打印使用的提示信息,并退出程序 */
if (strlen(argv[1]) != 11) {
printf(“The phone number is error\n”);
printf(“Usage: %s [phone number]\n”, argv[0]);
exit(1);
}
/* 用phonenum指针指向传入的电话号码字符串,方便后面发送短信使用 */
phonenum = argv[1];

/* 打开按键设备文件,开发板上有6个按键,可通过该文件来获取按键的值,
 * 这些按键可以用来模拟一些传感器发出的触发信号,比如检测到有人闯入,
 * 温度过高,电流过大等
 */
btn_fd = open(BTNS_DEV_PATH, O_RDONLY);
/* 如果文件打开失败,则打印错误信息,并退出程序 */
if (btn_fd == -1) {
perror(“Buttons”);
exit(1);
}

/* 打开LED设备文件,开发板上有4个LED灯,可通过该文件来点亮或熄灭LED灯,
 * 这些LED灯可以用来模拟家里的电器设备,比如空调,电视机等
 */
led_fd = open(LEDS_DEV_PATH, O_RDONLY);
/* 如果文件打开失败,则打印错误信息,并退出程序 */
if (btn_fd == -1) {
close(btn_fd);
perror(“LEDs”);
exit(1);
}

/* 初始化GPRS模块,串口的波特率为115200,数据位是8位,无奇偶校验,1位停止位 */
  ret = gprs_init(GPRS_DEV_PATH, B115200, CS8, “”n””, 1);
/* 如果初始化,则打印错误信息,并关闭前面打开的设备文件,然后退出程序 */
if (ret) {
printf(“Initialize gprs failed\n”);
close(led_fd);
close(btn_fd);
exit(1);
}

/* 创建一个主线程,把线程id存放在tinfo[0].id变量中,线程的属性没有特殊要求,
 * 线程函数为thread_main,线程函数参数为空。该线程用来检测按键的输入,并根据
 * 不同的按键来发送不同的短信。可以认为该线程是在检测各传感器的状态,如果传感器
 * 得到的值有异常的话,则发送短信。
 */
ret = pthread_create(&tinfo[0].id, NULL, thread_main, NULL);
/* 如果线程创建失败,则打印错误信息并退出程序 */
if (ret) {
perror(“main thread”);
close(led_fd);
close(btn_fd);
exit(1);
}   

/* 创建另外一个线程,线程函数是thread_gprs,该函数用来实时接收短信,并根据短信的内容
 * 来控制开发板上的LED及蜂鸣器,可以用来模拟家里的电器设备的控制和手动报警
 */
ret = pthread_create(&tinfo[1].id, NULL, thread_gprs, NULL);
/* 如果线程创建失败,则打印错误信息并退出程序 */
if (ret) {
perror(“gprs thread”);
close(led_fd);
close(btn_fd);
exit(1);
}

/* 用于等待第一个线程的结束,线程结束后回收其资源 */
if (tinfo[0].id != 0) {
pthread_join(tinfo[0].id, NULL);
printf(“The main thread has finished\n”);
}

/* 用于等待第二个线程的结束,线程结束后回收其资源 */
if (tinfo[1].id != 0) {
pthread_join(tinfo[1].id, NULL);
printf(“The gprs thread has finished\n”);
}

/* 两个线程如果因为异常结束,则主程序执行清理操作后退出 */
gprs_exit();
close(led_fd);
close(btn_fd);

return 0;
}

这不是已经写的很清楚了吗?
100分
代码功能归根结底不是别人帮自己看或讲解或注释出来的;而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。
提醒:再牛×的老师也无法代替学生自己领悟和上厕所!
单步调试和设断点调试(VS IDE中编译连接通过以后,按F10或F11键单步执行,按Shift+F11退出当前函数;在某行按F9设断点后按F5执行停在该断点处。)是程序员必须掌握的技能之一。
请问代码中很多东西我看不懂,虽然我的C代码量有1万行左右,请问我该如何着手。谢谢。

喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!