学前小故事一、Hello Digispark
1.硬件介绍2.实现原理3.配置环境4.第一个USB开发板程序 二、结构介绍以及C语言美化
1.#difine定义常量2.函数封装调用 三、强化学习
1.源码阅读2.源码总结 四、效果展示C语言其实很厉害认真学C的你真的很帅/美
学前小故事
大一上学期,学校完成了半本《C++黑皮书》的教学。我学会了打HelloWorld!!!
#includeint main() { printf("Hello World!n"); return 0;}
寒假,乘着对计算机的热情,我在家花了三天的时间,啃完了后半册《类和对象》。我学会了!!!
用结构体打HelloWorld…
#includestruct { char *str = "Hello World!"; } test; int main() { printf(test.str); return 0;}
这个黑不拉几的命令行是用来解小学奥数题的吗?这和炫酷好像差了亿点点啊?
后来,我就去学HTML画网页去了…
我在一堂讲座上听到了BadUSB。由于Bad这一单词太帅。
出于对计算机的强烈热爱。我在淘宝上斥20元巨资,买了两个最便宜的USB开发板。
最终,完成了一次C语言的实际应用,并对次项目的完成过程和出现的问题进行记录和完善。
一、Hello Digispark 1.硬件介绍
硬件:Attiny85 Digispark开发板,某宝10元上下浮动。
Attiny85 Digispark开发板可以模拟成日常使用的USB键盘进行模拟输入。
利用Win系统,按下WIN+R打开并锁定到CMD的特性,能够用cmd命令行代码做到诸如
在命令行打HELLO WORLD、打开一个网页、关闭电脑等事情。
所有操作只要事先编写好代码,在插入USB后会自动执行。
百度网盘链接(失效请联系我补链):https://pan.baidu.com/s/1_dSDderH-UtY0XozLq3WhQ?pwd=nbut
操作系统:Win7、10、11
驱动安装:DigisparkWindowsDriver
编译器:Arduino
(1) 解压DigisparkWindowsDriver,根据操作系统位数双击某个exe,安装相应的安装包。
(2) 解压Arduino,进入目录运行arduino.exe
(3)此步骤已在我的ZIP中封装好,可能可以省略,建议检查一遍。
打开左上方文件->首选项,在附加开发板管理网址中输入
http://digistump.com/package_digistump_index.json
科学上网后,打开工具->开发板->开发板管理,下载相应开发包。
4.第一个USB开发板程序在工具->开发板中选择Digispark(Defult - 16.5mhz)
在页面中输入以下代码。
#include "DigiKeyboard.h"
void setup() {
//第一步操作,打开cmd命令
DigiKeyboard.delay(2000);
DigiKeyboard.sendKeyStroke(0);
DigiKeyboard.sendKeyStroke(KEY_R, MOD_GUI_LEFT);//按R和win键,打开运行
//*****第二步操作,输入代码,多次实验得出的解决方案
//***此步骤适配系统为WIN10标准输入法,在中英文下皆可成功输入正确代码
//*输入字符请用print,切勿使用println,因为println会在输入完字符后在后面追加回车,括号中内容最好全用大写
DigiKeyboard.delay(200);
DigiKeyboard.sendKeyPress(MOD_SHIFT_LEFT);//按住shift
DigiKeyboard.print("HELLO");
DigiKeyboard.sendKeyPress(0);//松开shift
DigiKeyboard.sendKeyStroke(KEY_SPACE);
DigiKeyboard.sendKeyStroke(KEY_SPACE);//按两次空格,确保正确输入并有空行
DigiKeyboard.delay(200);
DigiKeyboard.sendKeyPress(MOD_SHIFT_LEFT);//按住shift
DigiKeyboard.print("DIGISPART");
DigiKeyboard.sendKeyPress(0);//松开shift
DigiKeyboard.sendKeyStroke(KEY_SPACE);
DigiKeyboard.sendKeyStroke(KEY_SPACE);//按两次空格,确保正确输入并有空行
//第三步操作,按下回车,此次作为测试盘不建议使用(也可以增加等待时间来测试)
// DigiKeyboard.delay(200);
// DigiKeyboard.sendKeyStroke(KEY_ENTER);//按回车
}
void loop() {
}
代码输入完成后,点击左上方的勾勾,会出现下方信息。
再点击勾勾旁边的箭头,并关闭奇怪的框框,会在下方出现黄色的,请在60s内插入开发板的提示。
立刻插入开发板,就会进行烧录并稍后执行相应命令。在电脑左下角出现下面情况即为完成第一个项目。
二、结构介绍以及C语言美化
相信学过C的都会想到,上面的HELLO WORLD程序虽然在格式上完全正确,但是好像差了点什么?
没错,就是重复代码太多了。要修改起来过于麻烦,下面1,2两步处理后也许会好看很多。
对于常用的重复变量,我们可以给它改个名字,让它变得好看又方便修改。
DigiKeyboard.delay(2000);
DigiKeyboard.sendKeyStroke(0);
DigiKeyboard.sendKeyStroke(KEY_R, MOD_GUI_LEFT);//按R和win键,打开运行
DigiKeyboard.delay(200);
DigiKeyboard.sendKeyPress(MOD_SHIFT_LEFT);//按住shift
DigiKeyboard.print("HELLO");
DigiKeyboard.sendKeyPress(0);//松开shift
DigiKeyboard.sendKeyStroke(KEY_SPACE);
DigiKeyboard.sendKeyStroke(KEY_SPACE);//按两次空格,确保正确输入并有空行
DigiKeyboard.delay(200);
DigiKeyboard.sendKeyPress(MOD_SHIFT_LEFT);//按住shift
DigiKeyboard.print("DIGISPART");
DigiKeyboard.sendKeyPress(0);//松开shift
DigiKeyboard.sendKeyStroke(KEY_SPACE);
DigiKeyboard.sendKeyStroke(KEY_SPACE);//按两次空格,确保正确输入并有空行
在HELLO WORLD代码中,我们不难发现,2000,200这两个变量时常出现,那么就可以用#define重新定义一下。在引用头文件下打上如下两行代码,将2000命名为LONG_TIME,代表长停顿时间,短停顿时间则命名为SHORT_TIME,这里我将SHORT_TIME改为100,代表0.1s。
#include "DigiKeyboard.h" #define LONG_TIME 2000 #define SHORT_TIME 1002.函数封装调用
再次观察HELLO WORLD代码,还可以发现,在输入单词阶段,有大量重复代码,那我们就可以创建一个新的函数,将它封装起来。下面是我封装完后的HELLO WORLD代码。
#include "DigiKeyboard.h"
#define LONG_TIME 2000
#define SHORT_TIME 100
void run_begin() {
DigiKeyboard.delay(LONG_TIME);//开机延迟两秒钟,用于系统识别Digispark
DigiKeyboard.sendKeyStroke(0);//适应老旧系统
DigiKeyboard.sendKeyStroke(KEY_R, MOD_GUI_LEFT);//按R和win键,打开运行
}
void str_print(char* str) {
DigiKeyboard.delay(SHORT_TIME);//停滞一段时间
DigiKeyboard.sendKeyPress(MOD_SHIFT_LEFT);//按住shift
DigiKeyboard.print(str);//*输出字符,内容大写
DigiKeyboard.sendKeyPress(0);//松开shift
DigiKeyboard.sendKeyStroke(KEY_SPACE);
DigiKeyboard.sendKeyStroke(KEY_SPACE);//按两次空格,确保正确输入并有空行
}
void run_end() {
DigiKeyboard.delay(SHORT_TIME);//停滞一段时间
DigiKeyboard.sendKeyStroke(KEY_ENTER);//按回车
}
void setup() {
run_begin();
str_print("HELLO");
str_print("-WORLD");
// run_end();
}
void loop() {
}
三、强化学习 1.源码阅读
读懂别人写的代码也是团队协作和成神的必要技能点。
已经被官方开发承认的头文件理所应当是阅读的首要材料。
欢迎来到<走进源码>栏目。一起剖析
此文件我复制了一个,放在了example文件夹中。
下面是部分源码:
#define MOD_CONTROL_LEFT (1<<0) #define MOD_SHIFT_LEFT (1<<1) #define MOD_ALT_LEFT (1<<2) #define MOD_GUI_LEFT (1<<3) #define MOD_CONTROL_RIGHT (1<<4) #define MOD_SHIFT_RIGHT (1<<5) #define MOD_ALT_RIGHT (1<<6) #define MOD_GUI_RIGHT (1<<7) #define KEY_A 4 #define KEY_B 5 #define KEY_C 6 #define KEY_D 7 #define KEY_E 8 #define KEY_F 9 #define KEY_G 10 #define KEY_H 11 #define KEY_I 12 #define KEY_J 13 #define KEY_K 14 #define KEY_L 15 #define KEY_M 16 #define KEY_N 17 #define KEY_O 18 #define KEY_P 19 #define KEY_Q 20 #define KEY_R 21 #define KEY_S 22 #define KEY_T 23 #define KEY_U 24 #define KEY_V 25 #define KEY_W 26 #define KEY_X 27 #define KEY_Y 28 #define KEY_Z 29 #define KEY_1 30 #define KEY_2 31 #define KEY_3 32 #define KEY_4 33 #define KEY_5 34 #define KEY_6 35 #define KEY_7 36 #define KEY_8 37 #define KEY_9 38 #define KEY_0 39 #define KEY_ENTER 40 #define KEY_SPACE 44
class DigiKeyboardDevice : public Print {
public:
DigiKeyboardDevice () {
cli();
usbDeviceDisconnect();
_delay_ms(250);
usbDeviceConnect();
usbInit();
sei();
// TODO: Remove the next two lines once we fix
// missing first keystroke bug properly.
memset(reportBuffer, 0, sizeof(reportBuffer));
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
void update() {
usbPoll();
}
// delay while updating until we are finished delaying
void delay(long milli) {
unsigned long last = millis();
while (milli > 0) {
unsigned long now = millis();
milli -= now - last;
last = now;
update();
}
}
//sendKeyStroke: sends a key press AND release
void sendKeyStroke(byte keyStroke) {
sendKeyStroke(keyStroke, 0);
}
//sendKeyStroke: sends a key press AND release with modifiers
void sendKeyStroke(byte keyStroke, byte modifiers) {
sendKeyPress(keyStroke, modifiers);
// This stops endlessly repeating keystrokes:
sendKeyPress(0,0);
}
//sendKeyPress: sends a key press only - no release
//to release the key, send again with keyPress=0
void sendKeyPress(byte keyPress) {
sendKeyPress(keyPress, 0);
}
//sendKeyPress: sends a key press only, with modifiers - no release
//to release the key, send again with keyPress=0
void sendKeyPress(byte keyPress, byte modifiers) {
while (!usbInterruptIsReady()) {
// Note: We wait until we can send keyPress
// so we know the previous keyPress was
// sent.
usbPoll();
_delay_ms(5);
}
memset(reportBuffer, 0, sizeof(reportBuffer));
reportBuffer[0] = modifiers;
reportBuffer[1] = keyPress;
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
size_t write(uint8_t chr) {
uint8_t data = pgm_read_byte_near(ascii_to_scan_code_table + (chr - 8));
sendKeyStroke(data & 0b01111111, data >> 7 ? MOD_SHIFT_RIGHT : 0);
return 1;
}
//private: TODO: Make friend?
uchar reportBuffer[2]; // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]
using Print::write;
};
2.源码总结
看懂了源码,可以对此进行归纳总结。下面是我的总结。
四、效果展示
Shutdown-H代码运行效果
C语言其实很厉害
C语言从出生开始基本没遇到过什么挑战。
对于C的具体语法。人们实在想不出整数类型除了用按字节数归类为char、short、int、long,还能怎么分类。
结构体好似恰到好处,往struct加什么都像是画蛇添足。
它的指针更为精妙,能完美地和数组配合起来。
基本的malloc和free似乎是内存管理的唯一方式。
函数调用和递归还是用调用栈实现。
虽然它没有现在的Python,Java,C#那么简单易学,但它依旧是游戏内核,硬件领域的龙头语言。
应为他的效率比它们都高!!!
黑乎乎的命令行有时真的很让人感到疲倦,但是它有时就像黑夜中的刺客,让人摸不着脑袋,又让人浮想联翩。不管你学C的目的是什么。
做游戏内核?成为算法大牛?做硬件工程师?写驱动程序进行多端适配?当一名坏坏的黑客?
祝你不忘初心,一路成神,这真的很帅,很美…



