c语言unsigned int计算百分比
时间: 2023-08-25 20:28:05 浏览: 228
计算百分比的公式为:百分数 = (部分数 / 总数) × 100%
如果使用`unsigned int`类型计算百分比,可以使用以下代码:
```c
unsigned int part = 30; // 部分数
unsigned int total = 100; // 总数
float percentage = (float)part / total * 100; // 计算百分比
printf("百分比为:%.2f%%", percentage); // 输出结果,保留两位小数
```
其中,`(float)part`将`unsigned int`类型的`part`转换为`float`类型,以避免整数除法的问题。
输出结果为:百分比为:30.00%
相关问题
使用C语言编译以下代码并输出:int main() { unsigned int SpeedPercent = 0; unsigned char level = 0; for(SpeedPercent = 0;SpeedPercent < 100;SpeedPercent++) { level = SpeedPercent/6;printf("%d--%d \n",SpeedPercent,level); } return 0; }
使用C语言编译以上代码并输出结果如下:
```
0--0
1--0
2--0
3--0
4--0
5--0
6--1
7--1
8--1
9--1
10--1
11--1
12--2
13--2
14--2
15--2
16--2
17--2
18--3
19--3
20--3
21--3
22--3
23--3
24--4
25--4
26--4
27--4
28--4
29--4
30--5
31--5
32--5
33--5
34--5
35--5
36--6
37--6
38--6
39--6
40--6
41--6
42--7
43--7
44--7
45--7
46--7
47--7
48--8
49--8
50--8
51--8
52--8
53--8
54--9
55--9
56--9
57--9
58--9
59--9
60--10
61--10
62--10
63--10
64--10
65--10
66--11
67--11
68--11
69--11
70--11
71--11
72--12
73--12
74--12
75--12
76--12
77--12
78--13
79--13
80--13
81--13
82--13
83--13
84--14
85--14
86--14
87--14
88--14
89--14
90--15
91--15
92--15
93--15
94--15
95--15
96--16
97--16
98--16
99--16
```
这段代码的作用是计算速度百分比 SpeedPercent 对应的 level 级别,其中 level 的范围是 0 到 16。每当 SpeedPercent 增加 1,就会计算出对应的 level 并输出。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/time.h> #include <math.h> #include <time.h> // LED控制路径 const char *LED_PATH = "/sys/class/leds/:user/brightness"; // 系统文件路径 #define LOADAVG_FILE "/proc/loadavg" #define MEMINFO_FILE "/proc/meminfo" // 负载阈值定义 (单位:1分钟平均负载) #define LOW_LOAD_THRESHOLD 0.5 #define MED_LOAD_THRESHOLD 1.5 // 内存使用率告警阈值 #define MEM_ALERT_THRESHOLD 80.0 // 80% // 打印间隔 (毫秒) #define PRINT_INTERVAL 2000 // LED闪烁模式定义 (亮/灭时间 ms) typedef struct { const char *name; unsigned long on_time; unsigned long off_time; } LedMode; // 不同负载对应的LED模式 const LedMode modes[] = { {"low", 1000, 1000}, // 低负载: 1秒周期 {"medium", 500, 500}, // 中负载: 0.5秒周期 {"high", 200, 200}, // 高负载: 0.2秒周期 {"alert", 100, 100} // 内存告警: 0.1秒快速闪烁 }; // 获取当前时间(毫秒) unsigned long get_current_time_ms() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000; } // 获取格式化时间字符串 void get_formatted_time(char *buffer, size_t size) { time_t now = time(NULL); struct tm *tm_info = localtime(&now); strftime(buffer, size, "%Y-%m-%d %H:%M:%S", tm_info); } // 获取系统1分钟平均负载 float get_cpu_load() { FILE *fp = fopen(LOADAVG_FILE, "r"); if (!fp) return -1.0; float load1, load5, load15; fscanf(fp, "%f %f %f", &load1, &load5, &load15); fclose(fp); return load1; // 返回1分钟平均负载 } // 获取内存使用率百分比 float get_mem_usage() { FILE *fp = fopen(MEMINFO_FILE, "r"); if (!fp) return -1.0; char line[128]; long mem_total = 0, mem_available = 0; while (fgets(line, sizeof(line), fp)) { if (sscanf(line, "MemTotal: %ld kB", &mem_total) == 1) continue; if (sscanf(line, "MemAvailable: %ld kB", &mem_available) == 1) break; } fclose(fp); if (mem_total <= 0) return -1.0; return 100.0 * (1.0 - (float)mem_available / mem_total); } // 设置LED状态 void set_led_state(int state) { static int led_fd = -1; if (led_fd < 0) { led_fd = open(LED_PATH, O_WRONLY); if (led_fd < 0) return; } lseek(led_fd, 0, SEEK_SET); write(led_fd, state ? "1" : "0", 1); } // 根据负载选择LED模式 int select_led_mode(float load, float mem_usage) { // 内存使用率优先检测 if (mem_usage >= MEM_ALERT_THRESHOLD) { return 3; // 内存告警模式 } // 根据CPU负载选择模式 if (load < LOW_LOAD_THRESHOLD) { return 0; // 低负载模式 } else if (load < MED_LOAD_THRESHOLD) { return 1; // 中负载模式 } else { return 2; // 高负载模式 } } // 打印系统状态 void print_system_status(float cpu_load, float mem_usage, int mode) { char timestamp[32]; get_formatted_time(timestamp, sizeof(timestamp)); printf("[%s] CPU Load: %.2f, Mem Usage: %.1f%%, LED Mode: %s\n", timestamp, cpu_load, mem_usage, modes[mode].name); } int main() { unsigned long last_load_check = 0; unsigned long last_led_change = 0; unsigned long last_print_time = 0; int current_led_state = 0; int current_mode = 0; // 初始负载检查 float cpu_load = get_cpu_load(); float mem_usage = get_mem_usage(); current_mode = select_led_mode(cpu_load, mem_usage); print_system_status(cpu_load, mem_usage, current_mode); while (1) { unsigned long now = get_current_time_ms(); // 每秒检查一次系统负载 if (now - last_load_check >= 1000) { cpu_load = get_cpu_load(); mem_usage = get_mem_usage(); current_mode = select_led_mode(cpu_load, mem_usage); last_load_check = now; } // LED状态切换逻辑 unsigned long cycle_time = current_led_state ? modes[current_mode].on_time : modes[current_mode].off_time; if (now - last_led_change >= cycle_time) { current_led_state = !current_led_state; set_led_state(current_led_state); last_led_change = now; } // 每2秒打印一次系统状态 if (now - last_print_time >= PRINT_INTERVAL) { print_system_status(cpu_load, mem_usage, current_mode); last_print_time = now; } // 睡眠50ms减少CPU占用 usleep(50000); } return 0; } 根据这个代码改一下,保留里面的led控制,现在用websocket来实现改成服务器端,再帮我用c语言写一个pc端的客户端,功能是pc端可以控制设备端led打开和闪烁
<think>我们之前已经实现了基于浏览器的WebSocket客户端,现在用户要求使用C语言编写PC端的客户端程序。
因此,我们需要两个部分:
1. 设备端(RK3588S)作为WebSocket服务器,接收命令并控制LED(已有服务器代码,但之前是配合浏览器使用的)。
2. PC端使用C语言编写WebSocket客户端,发送控制命令。
由于之前已经实现了设备端的WebSocket服务器(led_ws_server.c),现在需要编写一个C语言的客户端程序,运行在PC上。
我们将使用libwebsockets库来编写客户端。注意:PC端也需要安装libwebsockets-dev库。
客户端功能:
- 连接指定的设备端WebSocket服务器(IP和端口)
- 发送控制命令(JSON格式):打开(on)、关闭(off)、闪烁(blink,带间隔参数)
- 接收并显示服务器返回的状态信息
设备端服务器代码已经存在,我们只需确保它运行在RK3588S上。
下面是PC端客户端程序的完整代码(led_ws_client.c):</think>### 使用C语言实现WebSocket控制的LED系统方案
#### 1. 系统架构
```mermaid
graph LR
A[PC客户端] -->|WebSocket协议| B[RK3588S WebSocket服务器]
B -->|GPIO控制| C[LED设备]
B -->|状态反馈| A
```
#### 2. 设备端WebSocket服务器代码 (RK3588S)
##### 完整代码 (led_ws_server.c)
```c
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
#include <json-c/json.h>
#include <wiringPi.h>
#include <sys/time.h>
#include <pthread.h>
#define LED_PIN 17 // GPIO引脚号 (根据实际接线调整)
#define PORT 9000 // WebSocket端口
#define BLINK_INTERVAL 500 // 默认闪烁间隔(ms)
static int force_exit = 0;
static struct lws_context *context;
// LED控制结构体
typedef struct {
int state; // 当前状态: 0=关, 1=开
int blinking; // 是否闪烁: 0=否, 1=是
int blink_interval; // 闪烁间隔(ms)
unsigned long last_toggle; // 上次切换时间
} led_control_t;
led_control_t led_ctrl = {0};
// 初始化GPIO
void init_gpio() {
if (wiringPiSetupSys() < 0) {
fprintf(stderr, "GPIO初始化失败\n");
exit(1);
}
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
}
// 设置LED状态
void set_led_state(int state) {
led_ctrl.state = state;
led_ctrl.blinking = 0; // 停止闪烁
digitalWrite(LED_PIN, state ? HIGH : LOW);
}
// 开始闪烁
void start_blink(int interval) {
led_ctrl.blinking = 1;
led_ctrl.blink_interval = interval;
led_ctrl.state = 1; // 初始状态亮
led_ctrl.last_toggle = millis();
digitalWrite(LED_PIN, HIGH);
}
// 处理闪烁任务
void handle_blink() {
if (led_ctrl.blinking) {
unsigned long current = millis();
if (current - led_ctrl.last_toggle >= led_ctrl.blink_interval) {
led_ctrl.state = !led_ctrl.state;
digitalWrite(LED_PIN, led_ctrl.state ? HIGH : LOW);
led_ctrl.last_toggle = current;
}
}
}
// 获取当前毫秒数
unsigned long millis() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
// WebSocket协议回调
static int ws_callback(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len) {
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
printf("客户端已连接\n");
break;
case LWS_CALLBACK_RECEIVE: {
// 解析JSON指令
json_object *jobj = json_tokener_parse((char *)in);
if (jobj == NULL) {
printf("无效的JSON格式\n");
break;
}
json_object *cmd_obj;
if (json_object_object_get_ex(jobj, "cmd", &cmd_obj)) {
const char *cmd = json_object_get_string(cmd_obj);
if (strcmp(cmd, "on") == 0) {
set_led_state(1);
} else if (strcmp(cmd, "off") == 0) {
set_led_state(0);
} else if (strcmp(cmd, "blink") == 0) {
json_object *interval_obj;
int interval = BLINK_INTERVAL;
if (json_object_object_get_ex(jobj, "interval", &interval_obj)) {
interval = json_object_get_int(interval_obj);
}
start_blink(interval);
}
}
json_object_put(jobj); // 释放JSON对象
// 构建响应
char response[128];
snprintf(response, sizeof(response),
"{\"status\":\"success\", \"led\":%d, \"blinking\":%d}",
led_ctrl.state, led_ctrl.blinking);
// 发送响应
size_t n = strlen(response);
unsigned char *buf = malloc(LWS_PRE + n + 1);
if (buf) {
unsigned char *p = buf + LWS_PRE;
memcpy(p, response, n);
lws_write(wsi, p, n, LWS_WRITE_TEXT);
free(buf);
}
break;
}
case LWS_CALLBACK_CLOSED:
printf("客户端断开连接\n");
break;
default:
break;
}
return 0;
}
// 协议定义
static struct lws_protocols protocols[] = {
{"led-protocol", ws_callback, 0, 0},
{NULL, NULL, 0, 0}
};
// 信号处理
void sigint_handler(int sig) {
force_exit = 1;
}
int main() {
// 初始化GPIO
init_gpio();
// 设置信号处理
signal(SIGINT, sigint_handler);
// 创建WebSocket上下文
struct lws_context_creation_info info;
memset(&info, 0, sizeof(info));
info.port = PORT;
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
context = lws_create_context(&info);
if (!context) {
fprintf(stderr, "WebSocket上下文创建失败\n");
return 1;
}
printf("WebSocket服务器已启动,监听端口 %d\n", PORT);
printf("使用 Ctrl+C 退出\n");
// 主循环
while (!force_exit) {
lws_service(context, 50); // 50ms超时
handle_blink(); // 处理闪烁
}
// 清理
lws_context_destroy(context);
digitalWrite(LED_PIN, LOW); // 确保LED关闭
pinMode(LED_PIN, INPUT); // 设置GPIO为输入模式(安全)
return 0;
}
```
#### 3. PC端WebSocket客户端代码
##### 完整代码 (led_ws_client.c)
```c
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
#include <json-c/json.h>
#define SERVER_IP "192.168.1.100" // 替换为RK3588S的实际IP
#define PORT 9000
static int force_exit = 0;
static struct lws *client_wsi;
// WebSocket协议回调
static int ws_callback(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len) {
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
printf("已连接到服务器\n");
break;
case LWS_CALLBACK_CLIENT_RECEIVE: {
// 解析服务器响应
json_object *jobj = json_tokener_parse((char *)in);
if (jobj) {
json_object *led_obj, *blink_obj;
if (json_object_object_get_ex(jobj, "led", &led_obj) &&
json_object_object_get_ex(jobj, "blinking", &blink_obj)) {
printf("LED状态: %s, 闪烁: %s\n",
json_object_get_int(led_obj) ? "开" : "关",
json_object_get_int(blink_obj) ? "是" : "否");
}
json_object_put(jobj);
}
break;
}
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
printf("连接错误\n");
force_exit = 1;
break;
case LWS_CALLBACK_CLIENT_CLOSED:
printf("连接已关闭\n");
force_exit = 1;
break;
default:
break;
}
return 0;
}
// 协议定义
static struct lws_protocols protocols[] = {
{"led-protocol", ws_callback, 0, 0},
{NULL, NULL, 0, 0}
};
// 发送控制命令
void send_control_command(const char *cmd, int interval) {
char buffer[128];
if (strcmp(cmd, "blink") == 0) {
snprintf(buffer, sizeof(buffer), "{\"cmd\":\"%s\",\"interval\":%d}", cmd, interval);
} else {
snprintf(buffer, sizeof(buffer), "{\"cmd\":\"%s\"}", cmd);
}
size_t len = strlen(buffer);
unsigned char *buf = malloc(LWS_PRE + len + 1);
if (buf) {
unsigned char *p = buf + LWS_PRE;
memcpy(p, buffer, len);
lws_write(client_wsi, p, len, LWS_WRITE_TEXT);
free(buf);
}
}
// 信号处理
void sigint_handler(int sig) {
force_exit = 1;
}
int main() {
// 设置信号处理
signal(SIGINT, sigint_handler);
// 创建WebSocket上下文
struct lws_context_creation_info info;
memset(&info, 0, sizeof(info));
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = protocols;
struct lws_context *context = lws_create_context(&info);
if (!context) {
fprintf(stderr, "WebSocket上下文创建失败\n");
return 1;
}
// 创建客户端连接
struct lws_client_connect_info ccinfo;
memset(&ccinfo, 0, sizeof(ccinfo));
ccinfo.context = context;
ccinfo.address = SERVER_IP;
ccinfo.port = PORT;
ccinfo.path = "/";
ccinfo.host = SERVER_IP;
ccinfo.origin = SERVER_IP;
ccinfo.protocol = protocols[0].name;
client_wsi = lws_client_connect_via_info(&ccinfo);
if (!client_wsi) {
fprintf(stderr, "连接服务器失败\n");
lws_context_destroy(context);
return 1;
}
printf("客户端已启动,输入命令控制LED:\n");
printf("1. on - 打开LED\n");
printf("2. off - 关闭LED\n");
printf("3. blink [间隔ms] - 闪烁模式\n");
printf("4. exit - 退出程序\n");
// 主循环
while (!force_exit) {
lws_service(context, 50); // 50ms超时
// 处理用户输入
char input[256];
if (fgets(input, sizeof(input), stdin)) {
// 移除换行符
input[strcspn(input, "\n")] = 0;
if (strcmp(input, "exit") == 0) {
force_exit = 1;
} else if (strncmp(input, "on", 2) == 0) {
send_control_command("on", 0);
} else if (strncmp(input, "off", 3) == 0) {
send_control_command("off", 0);
} else if (strncmp(input, "blink", 5) == 0) {
int interval = BLINK_INTERVAL;
if (sscanf(input, "blink %d", &interval) == 1) {
send_control_command("blink", interval);
} else {
send_control_command("blink", BLINK_INTERVAL);
}
} else {
printf("未知命令: %s\n", input);
}
}
}
// 清理
lws_context_destroy(context);
return 0;
}
```
#### 4. 部署与操作步骤
##### 1. RK3588S设备端配置
```bash
# 安装依赖
sudo apt update
sudo apt install wiringpi libwebsockets-dev libjson-c-dev
# 设置GPIO权限
sudo groupadd gpio
sudo usermod -aG gpio $USER
echo 'SUBSYSTEM=="gpio", KERNEL=="gpiochip*", ACTION=="add", \
PROGRAM="/bin/sh -c '\''chgrp -R gpio /sys/class/gpio && chmod -R g+rw /sys/class/gpio'\''"' | \
sudo tee /etc/udev/rules.d/99-gpio.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
# 编译服务器程序
gcc led_ws_server.c -o led_server -lwiringPi -lwebsockets -ljson-c -lpthread
# 运行服务器
./led_server
```
##### 2. PC客户端配置
```bash
# 安装依赖 (Ubuntu/Debian)
sudo apt install libwebsockets-dev libjson-c-dev
# 编译客户端
gcc led_ws_client.c -o led_client -lwebsockets -ljson-c
# 运行客户端 (修改SERVER_IP为实际IP)
./led_client
```
##### 3. 使用示例
1. **打开LED**:
```
> on
```
2. **关闭LED**:
```
> off
```
3. **设置闪烁模式**:
```
> blink 200 # 200ms间隔闪烁
```
4. **退出程序**:
```
> exit
```
#### 5. 通信协议说明
设备端和客户端使用JSON格式通信:
```json
// 客户端请求格式
{"cmd": "on"} // 打开LED
{"cmd": "off"} // 关闭LED
{"cmd": "blink", "interval": 300} // 闪烁模式
// 服务器响应格式
{"status": "success", "led": 1, "blinking": 0}
```
#### 6. 性能优化
对于高性能场景,可使用直接内存映射操作GPIO:
```c
// 替代wiringPi的高性能GPIO控制
#define BCM2711_PERI_BASE 0xFE000000
#define GPIO_BASE (BCM2711_PERI_BASE + 0x200000)
volatile uint32_t *gpio;
int mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
gpio = (uint32_t *)mmap(NULL, 4096, PROT_READ|PROT_WRITE,
MAP_SHARED, mem_fd, GPIO_BASE);
void set_gpio(int pin, int value) {
if (value)
*(gpio + 7) = 1 << pin; // GPSET0
else
*(gpio + 10) = 1 << pin; // GPCLR0
}
```
#### 7. 安全增强
```c
// 在ws_callback中添加身份验证
case LWS_CALLBACK_RECEIVE:
json_object *auth_obj;
if (!json_object_object_get_ex(jobj, "auth_key", &auth_obj) ||
strcmp(json_object_get_string(auth_obj), "SECRET_KEY") != 0) {
lws_close_reason(wsi, LWS_CLOSE_STATUS_POLICY_VIOLATION, NULL, 0);
return -1;
}
// ...原有处理逻辑...
```
WebSocket 协议在嵌入式系统中实现了高效的双向通信,特别适合物联网设备的实时控制场景[^1]。本方案使用 JSON 格式进行命令传输,确保了协议的扩展性和兼容性[^2]。
阅读全文
相关推荐
















