# HJ_C52项目 **Repository Path**: ArsSama/hj-c52-project ## Basic Information - **Project Name**: HJ_C52项目 - **Description**: -----入门51单片机----- - **Primary Language**: C - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2024-05-08 - **Last Updated**: 2024-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HJ_C52C随笔 ### 多任务调度 多任务采用周期性调度,周期计算使用定时器0来进行. ``` 下面为该多任务调度的使用方法: /* define your task func start */ #define TASK_NUM 3 static void task_1(void); static void task_2(void); static void task_3(void); /* define your task func end */ /* define your task handle start */ static volatile task_t task_panel[TASK_NUM]; /* define your task handle end */ /** * @brief task_0 * */ static void task_0(void) { printf("task 0\r\n"); } /** * @brief task_1 * */ static void task_1(void) { printf("task 1\r\n"); } /** * @brief task_2 * */ static void task_2(void) { printf("task 2\r\n"); } /** * @brief task_creat * */ void task_creat(void) { uint8_t i; /* component init start */ /* component init end */ /* create task 0 start */ task_panel[0].operation = task_0; task_panel[0].period = 50; task_panel[0].tick = task_panel[0].period; /* create task 0 end */ /* create task 1 start */ task_panel[1].operation = task_1; task_panel[1].period = 100; task_panel[1].tick = task_panel[1].period; /* create task 1 end */ /* create task 2 start */ task_panel[2].operation = task_2; task_panel[2].period = 150; task_panel[2].tick = task_panel[2].period; /* create task 2 end */ for (i = 0; i < TASK_NUM; i++) { if (task_panel[i].operation != NULL) { printf("task_%bd create ok.[period = %d , tick = %d]\r\n", i, task_panel[i].period, task_panel[i].tick); } else { printf("task_%bd create fail.[task func is null]\r\n", i); } } } ``` ### 串口打印调试 ##### 串口打印方式 串口这里直接使用了putchar重定向printf输出,故若要使用串口打印数据则直接使用printf即可。 ##### 该方式的优缺点 优点:使用串口输出调试相对简单,不需要考虑一个一个字符去打印; 缺点:使用该printf的重定向内存消耗是需要的,且该方式相比直接输出效率会更低。 ##### 串口打印需要注意事项 ``` 注意事项1: [ %d整型输出,%ld长整型输出, %o以八进制数形式输出整数, %x以十六进制数形式输出整数, %u以十进制数输出unsigned型数据(无符号数)。 %c用来输出一个字符, %s用来输出一个字符串, %f用来输出实数,以小数形式输出 %.4f用来输出实数,保留小数点4位。 %e以指数形式输出实数, %g根据大小自动选f格式或e格式,且不输出无意义的零。 ] 注意事项2: [ [ b,h,l来对输出字节宽的设置 ] [ 一个单字节变量时要使用%bd ] 1. b八位 2. h十六位 3. l三十二位 %d 两个字节变量 int %bd 单字节变量 char %ld 四字节变量 long int ] ``` ##### 51数据表 ![51数据表](C_Test_Pro/static_png/Keil编译中C51数据类型列表.png) ### 独立按键组 ##### 独立按键组与串口冲突注意事项 由于C52的串口为P30和P31,故为避免冲突,本程序的使用预编译条件判断是否启动串口. ``` i_key.h ... #define UART_USED 1/* !> uart0 is used? */ ``` ##### 独立按键组使用方法 1. 在i_key.c文件里面修改预编译值[KEY_NUM]为具体独立按键的个数; 2. 在i_key.c文件里面修改[KEY_0]到[KEY_n]所对应的引脚; 3. 对于[KEY_0]到[KEY_n]需要多删少补; 4. 需要按键进行条件判断可在函数key_test(KEY_MSG *key_msg)里运行; 5. 最后仅需要运行函数i_key_scan_proc(void)即可. [推荐扫描周期为10-100ms] ##### 独立按键组非阻塞扫描方式 该扫描方式使用了非阻塞式扫描; 每次需要快速扫描多个独立按键的状态并记录,再与上次扫描的状态进行对比,有变化则为PRESSED,否则为RELEASED. ##### 独立按键组非阻塞扫描方式优缺点 优点: 速度快,效率高. 相比阻塞式扫描提高了CPU的利用率. 缺点: 会多占用内存. 比较需要存储对应按键通道的状态. ### PCF8591模数转换器 ##### ADC使用方法 ``` /* 调用pcf8591_read_adc()函数即可读取参数对应的通道AD值 */ void pcf8591_adc_demo() { pcf8591_adc_struct_panel()->adc_channel_0 = pcf8591_read_adc(PCF8591_ADC_CHANNEL_0); pcf8591_adc_struct_panel()->adc_channel_1 = pcf8591_read_adc(PCF8591_ADC_CHANNEL_1); pcf8591_adc_struct_panel()->adc_channel_2 = pcf8591_read_adc(PCF8591_ADC_CHANNEL_2); pcf8591_adc_struct_panel()->adc_channel_3 = pcf8591_read_adc(PCF8591_ADC_CHANNEL_3); printf("ADC_0:%bu\r\nADC_1:%bu\r\nADC_2:%bu\r\nADC_3:%bu\r\n", pcf8591_adc_struct_panel()->adc_channel_0, pcf8591_adc_struct_panel()->adc_channel_1, pcf8591_adc_struct_panel()->adc_channel_2, pcf8591_adc_struct_panel()->adc_channel_3); } ``` ##### DAC使用方法 ``` /* pcf8591_set_dac()函数即可设置输入参数并输出对应的DA值 */ /* 此处demo实现的是一个呼吸灯效果 */ static uint8_t pcf8591_dac = 0; static bit dac_fade = 0; void pcf8591_dac_demo() { if (pcf8591_dac == 255) { dac_fade = 1; } else if (pcf8591_dac == 0) { dac_fade = 0; } if (dac_fade) { pcf8591_dac -= 5; } else { pcf8591_dac += 5; } pcf8591_set_dac(pcf8591_dac); } ``` ##### 注意事项 1. 在读周期传输的第一个字节包含前一次读周期的转换结果代码 [简单来说就是,在读取一个通道的数据前,需要读取一次并舍去该数据,第二次读取的才是本次读取的数据] 2. 以上电复位之后读取的第一个字节是0x80。 ### AT24C02-EEPROM存储器 ##### AT24C02使用方法 ``` /* define your data start */ static uint8_t at24_count_demo = 0; /* define your data end */ void at24_wr_rd_demo(void) { at24c02_write_byte(0x01, at24_count_demo++); //写入数据 at24c02_read_data(0x01, &at24_count_demo); //读取数据 lcd1602_display_str(0, 0, "AT24C02-0x01-"); lcd1602_display_one_num(0, 14, at24_count_demo / 100); lcd1602_display_one_num(0, 15, (at24_count_demo % 100) / 10); lcd1602_display_one_num(0, 16, at24_count_demo % 10); #if AT24C02_DEBUG printf("read: [%bu]->%bu\r\n", 0x01, at24_count_demo); #endif } ``` ### DS18B20温度传感器 ##### DS18B20使用方法 ``` char lcd_dis_str[10]; ds18b20_proc(); sprintf(lcd_dis_str, "%.2fC", ds18b20_struct_panel()->temp_value); lcd1602_display_str(0, 0, "TEMP:"); lcd1602_display_str(5, 0, lcd_dis_str); ```