| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/io.h>
- #include <signal.h>
- #include <string.h>
- #define PORT_80 0x80
- #define SCAN_DELAY 5000 // 5ms扫描延时
- // 7段数码管段码表 (共阴极)
- const unsigned char segment_codes[] = {
- 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, // 0-7
- 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, // 8-F
- 0x00, 0x40 // 熄灭, 横杠
- };
- typedef struct {
- int running;
- int display_value;
- } DisplayContext;
- DisplayContext ctx = {1, 0};
- // 信号处理函数
- void signal_handler(int sig) {
- printf("\n正在退出...\n");
- ctx.running = 0;
- outb(0x00, PORT_80); // 清空显示
- }
- // 初始化I/O权限
- int init_io() {
- if (iopl(3) < 0) {
- perror("iopl failed");
- return -1;
- }
-
- // 或者使用ioperm(更精确的权限控制)
- // if (ioperm(PORT_80, 2, 1) < 0) {
- // perror("ioperm failed");
- // return -1;
- // }
-
- return 0;
- }
- // 显示单个数字在指定位置
- void display_digit(int digit, int position) {
- unsigned char code;
-
- if (digit < 0 || digit > 15) {
- code = segment_codes[16]; // 熄灭
- } else {
- code = segment_codes[digit];
- }
-
- // 位置0使用低4位,位置1使用高4位(取决于硬件连接)
- if (position == 0) {
- outb(code, PORT_80);
- } else {
- outb(code, PORT_80);
- }
- }
- // 显示两位数字
- void display_two_digits(int num) {
- char value = num & 0xff;
- outb(value, PORT_80);
- return;
- int tens = num / 10;
- int ones = num % 10;
- int scan_count = 50; // 扫描次数
-
- for (int i = 0; i < scan_count && ctx.running; i++) {
- // 显示十位
- outb(segment_codes[tens], PORT_80);
- usleep(SCAN_DELAY);
-
- // 显示个位
- outb(segment_codes[ones], PORT_80);
- usleep(SCAN_DELAY);
- }
- }
- // 显示16进制数字
- void display_hex(int value) {
- char values = value & 0xff;
- outb(values, PORT_80);
- return;
- // for (int i = 0; i < 50 && ctx.running; i++) {
- // outb(segment_codes[high], PORT_80);
- // usleep(SCAN_DELAY);
-
- // outb(segment_codes[low], PORT_80);
- // usleep(SCAN_DELAY);
- // }
- }
- // 特效显示:闪烁
- void blink_display(int num, int times) {
- for (int i = 0; i < times && ctx.running; i++) {
- display_two_digits(num);
- usleep(500000); // 500ms
-
- outb(0x00, PORT_80);
- usleep(300000); // 300ms
- }
- }
- // 特效显示:滚动
- void scroll_display(const char *text) {
- int len = strlen(text);
-
- for (int i = 0; i <= len && ctx.running; i++) {
- for (int j = 0; j < 20 && ctx.running; j++) {
- if (i < len) {
- int digit = text[i] - '0';
- if (digit >= 0 && digit <= 9) {
- outb(segment_codes[digit], PORT_80);
- }
- }
- usleep(SCAN_DELAY);
- }
- }
- }
- int main(int argc, char *argv[]) {
- int choice = 0;
- int value;
-
- printf("\n=== Intel ADL N97 Port 80 数码管控制程序 ===\n");
- printf("版本: 1.0\n");
- printf("平台: Ubuntu 22.04\n\n");
-
- // 初始化I/O权限
- if (init_io() < 0) {
- printf("错误: 无法获取I/O权限,请使用sudo运行\n");
- return 1;
- }
-
- // 设置信号处理
- signal(SIGINT, signal_handler);
-
- // 测试硬件连接
- printf("正在测试硬件连接...\n");
- for (int i = 0; i < 3 && ctx.running; i++) {
- outb(0xFF, PORT_80); // 全亮
- usleep(300000);
- outb(0x00, PORT_80); // 全灭
- usleep(200000);
- }
- printf("测试完成\n\n");
-
- while (ctx.running) {
- printf("\n请选择模式:\n");
- printf("1. 显示数字 (0-99)\n");
- printf("2. 显示16进制 (00-FF)\n");
- printf("3. 闪烁显示\n");
- printf("4. 滚动显示\n");
- printf("5. 计数器\n");
- printf("6. 退出\n");
- printf("选择: ");
-
- if (scanf("%d", &choice) != 1) {
- while(getchar() != '\n');
- continue;
- }
-
- switch(choice) {
- case 1:
- printf("输入数字 (0-99): ");
- scanf("%d", &value);
- if (value >= 0 && value <= 99) {
- printf("显示 %d\n", value);
- display_two_digits(value);
- }
- break;
-
- case 2:
- printf("输入16进制值 (00-FF): ");
- scanf("%x", &value);
- if (value >= 0 && value <= 0xFF) {
- printf("显示 0x%02X\n", value);
- display_hex(value);
- }
- break;
-
- case 3:
- printf("输入数字和闪烁次数: ");
- scanf("%d %d", &value, &choice);
- blink_display(value, choice);
- break;
-
- case 4:
- printf("输入数字串: ");
- char text[10];
- scanf("%s", text);
- scroll_display(text);
- break;
-
- case 5:
- printf("计数器模式 (按Ctrl+C退出)\n");
- for (int i = 0; i <= 99 && ctx.running; i++) {
- printf("\r计数: %d", i);
- fflush(stdout);
- display_two_digits(i);
- }
- printf("\n");
- break;
-
- case 6:
- ctx.running = 0;
- break;
-
- default:
- printf("无效选择\n");
- }
- }
-
- // 清理
- outb(0x00, PORT_80);
- printf("\n程序退出\n");
-
- return 0;
- }
|