test_ssegment.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/io.h>
  5. #include <signal.h>
  6. #include <string.h>
  7. #define PORT_80 0x80
  8. #define SCAN_DELAY 5000 // 5ms扫描延时
  9. // 7段数码管段码表 (共阴极)
  10. const unsigned char segment_codes[] = {
  11. 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, // 0-7
  12. 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, // 8-F
  13. 0x00, 0x40 // 熄灭, 横杠
  14. };
  15. typedef struct {
  16. int running;
  17. int display_value;
  18. } DisplayContext;
  19. DisplayContext ctx = {1, 0};
  20. // 信号处理函数
  21. void signal_handler(int sig) {
  22. printf("\n正在退出...\n");
  23. ctx.running = 0;
  24. outb(0x00, PORT_80); // 清空显示
  25. }
  26. // 初始化I/O权限
  27. int init_io() {
  28. if (iopl(3) < 0) {
  29. perror("iopl failed");
  30. return -1;
  31. }
  32. // 或者使用ioperm(更精确的权限控制)
  33. // if (ioperm(PORT_80, 2, 1) < 0) {
  34. // perror("ioperm failed");
  35. // return -1;
  36. // }
  37. return 0;
  38. }
  39. // 显示单个数字在指定位置
  40. void display_digit(int digit, int position) {
  41. unsigned char code;
  42. if (digit < 0 || digit > 15) {
  43. code = segment_codes[16]; // 熄灭
  44. } else {
  45. code = segment_codes[digit];
  46. }
  47. // 位置0使用低4位,位置1使用高4位(取决于硬件连接)
  48. if (position == 0) {
  49. outb(code, PORT_80);
  50. } else {
  51. outb(code, PORT_80);
  52. }
  53. }
  54. // 显示两位数字
  55. void display_two_digits(int num) {
  56. char value = num & 0xff;
  57. outb(value, PORT_80);
  58. return;
  59. int tens = num / 10;
  60. int ones = num % 10;
  61. int scan_count = 50; // 扫描次数
  62. for (int i = 0; i < scan_count && ctx.running; i++) {
  63. // 显示十位
  64. outb(segment_codes[tens], PORT_80);
  65. usleep(SCAN_DELAY);
  66. // 显示个位
  67. outb(segment_codes[ones], PORT_80);
  68. usleep(SCAN_DELAY);
  69. }
  70. }
  71. // 显示16进制数字
  72. void display_hex(int value) {
  73. char values = value & 0xff;
  74. outb(values, PORT_80);
  75. return;
  76. // for (int i = 0; i < 50 && ctx.running; i++) {
  77. // outb(segment_codes[high], PORT_80);
  78. // usleep(SCAN_DELAY);
  79. // outb(segment_codes[low], PORT_80);
  80. // usleep(SCAN_DELAY);
  81. // }
  82. }
  83. // 特效显示:闪烁
  84. void blink_display(int num, int times) {
  85. for (int i = 0; i < times && ctx.running; i++) {
  86. display_two_digits(num);
  87. usleep(500000); // 500ms
  88. outb(0x00, PORT_80);
  89. usleep(300000); // 300ms
  90. }
  91. }
  92. // 特效显示:滚动
  93. void scroll_display(const char *text) {
  94. int len = strlen(text);
  95. for (int i = 0; i <= len && ctx.running; i++) {
  96. for (int j = 0; j < 20 && ctx.running; j++) {
  97. if (i < len) {
  98. int digit = text[i] - '0';
  99. if (digit >= 0 && digit <= 9) {
  100. outb(segment_codes[digit], PORT_80);
  101. }
  102. }
  103. usleep(SCAN_DELAY);
  104. }
  105. }
  106. }
  107. int main(int argc, char *argv[]) {
  108. int choice = 0;
  109. int value;
  110. printf("\n=== Intel ADL N97 Port 80 数码管控制程序 ===\n");
  111. printf("版本: 1.0\n");
  112. printf("平台: Ubuntu 22.04\n\n");
  113. // 初始化I/O权限
  114. if (init_io() < 0) {
  115. printf("错误: 无法获取I/O权限,请使用sudo运行\n");
  116. return 1;
  117. }
  118. // 设置信号处理
  119. signal(SIGINT, signal_handler);
  120. // 测试硬件连接
  121. printf("正在测试硬件连接...\n");
  122. for (int i = 0; i < 3 && ctx.running; i++) {
  123. outb(0xFF, PORT_80); // 全亮
  124. usleep(300000);
  125. outb(0x00, PORT_80); // 全灭
  126. usleep(200000);
  127. }
  128. printf("测试完成\n\n");
  129. while (ctx.running) {
  130. printf("\n请选择模式:\n");
  131. printf("1. 显示数字 (0-99)\n");
  132. printf("2. 显示16进制 (00-FF)\n");
  133. printf("3. 闪烁显示\n");
  134. printf("4. 滚动显示\n");
  135. printf("5. 计数器\n");
  136. printf("6. 退出\n");
  137. printf("选择: ");
  138. if (scanf("%d", &choice) != 1) {
  139. while(getchar() != '\n');
  140. continue;
  141. }
  142. switch(choice) {
  143. case 1:
  144. printf("输入数字 (0-99): ");
  145. scanf("%d", &value);
  146. if (value >= 0 && value <= 99) {
  147. printf("显示 %d\n", value);
  148. display_two_digits(value);
  149. }
  150. break;
  151. case 2:
  152. printf("输入16进制值 (00-FF): ");
  153. scanf("%x", &value);
  154. if (value >= 0 && value <= 0xFF) {
  155. printf("显示 0x%02X\n", value);
  156. display_hex(value);
  157. }
  158. break;
  159. case 3:
  160. printf("输入数字和闪烁次数: ");
  161. scanf("%d %d", &value, &choice);
  162. blink_display(value, choice);
  163. break;
  164. case 4:
  165. printf("输入数字串: ");
  166. char text[10];
  167. scanf("%s", text);
  168. scroll_display(text);
  169. break;
  170. case 5:
  171. printf("计数器模式 (按Ctrl+C退出)\n");
  172. for (int i = 0; i <= 99 && ctx.running; i++) {
  173. printf("\r计数: %d", i);
  174. fflush(stdout);
  175. display_two_digits(i);
  176. }
  177. printf("\n");
  178. break;
  179. case 6:
  180. ctx.running = 0;
  181. break;
  182. default:
  183. printf("无效选择\n");
  184. }
  185. }
  186. // 清理
  187. outb(0x00, PORT_80);
  188. printf("\n程序退出\n");
  189. return 0;
  190. }