上期说到,我们发现第一版设计中MCP4017数字电位器无法直接应用于运算放大器的反馈电阻,设计时并没有考虑到MCP4017的电气特性,因此导致原理图作废。
同时我们发现在嘉立创EDA中,AD8034与AD8033的原理图存在混淆,导致型号选择错误。
在解决完这些事情之后,对装置进行了焊接和软件编程以及测试过程。
1、装置存在的问题
首先是可能由于放大倍数过大以及偏置电流的问题,导致输出存在着一个直流偏置,这个直流偏置是运算放大器引入的并非是AD9833的输出偏置被放大了。
应当在第一级放大后加交流耦合,防止直流偏置被进一步放大。
除此之外,又被嘉立创的库给坑了,到底是哪些神人在嘉立创上上面绘制错误的原理图和封装!!!
由于我没用过BNC母座,我其实在绘制的时候就有疑问,为什么输出引脚不是和SMA座子那种一样,输出引脚在中间,而是选择了边上?但是我以为BNC母座的特性就是这样子的,太过于相信这个封装了!!!
导致我在最后测试完毕,焊接上输出端口的时候,运放的输出直接接地!
2、装置大体
装置采用U8g2作为OLED的GUI库,两颗旋转编码器分别用来调节频率大小和频率位置 以及电压大小。
频率和幅度都可以正常改变,就是频率高的时候幅值会有一点衰减。
3、代码解析
AD9833_Init();//AD9833初始化HAL_Delay(100);AT24C02_LoadData(¤t_freq, ¤t_vol,&freq_unit);//读取频率和电压if(current_freq>=1000)//判断频率范围{freq_unit = 1;}UpdateFreqDigitsFromFreq();//更新显示数字AD9833_SetFrequency(current_freq);//设置频率AD9833_SetWave(WAVE_SINE);//设置AD9833波形MCP4017_SetWiper(current_vol);//设置电压HAL_TIM_Base_Start_IT(&htim1);//启用定时器HAL_TIM_Base_Start(&htim2);HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_1 | TIM_CHANNEL_2);//启用编码器HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_1 | TIM_CHANNEL_2);//启用编码器u8g2_t u8g2; //定义u8g2句柄u8g2Init(&u8g2);//u8g2初始化
初始化阶段包括对AD9833的初始化,从EEPROM中读取上次的频率和电压大小,AD9833频率设置,数字电位器档位设置以及U8g2的初始化。
while (1){if(save_flag){save_flag = 0;AT24C02_SaveData(current_freq, current_vol, freq_unit);}MainGUI(&u8g2);HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_2);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}
在主函数中进行U8g2的更新以及AT24C02的存储。
voidMainGUI(u8g2_t *u8g2){char freq_str[3];char vol_str[10];char unit_str[3];blink_counter++;uint8_t blink_state = (blink_counter % 10) < 5;u8g2_ClearBuffer(u8g2);u8g2_SetFont(u8g2, u8g2_font_ncenB12_tf);u8g2_DrawStr(u8g2, 5, 20, "Fre:");u8g2_SetFont(u8g2, u8g2_font_ncenB12_tf);for(uint8_t i = 0; i < 3; i++){if(edit_mode == 1 && freq_digit == i && !blink_state){u8g2_DrawHLine(u8g2, 45 + i * 9, 21, 7);continue;}freq_str[0] = freq_digits[i] + '0';freq_str[1] = '';u8g2_DrawStr(u8g2, 45 + i * 9, 20, freq_str);}u8g2_DrawStr(u8g2, 72, 20, ".");if(edit_mode == 1 && freq_digit == 3 && !blink_state){u8g2_DrawHLine(u8g2, 81, 21, 7);}else{freq_str[0] = freq_digits[3] + '0';freq_str[1] = '';u8g2_DrawStr(u8g2, 81, 20, freq_str);}if(freq_unit == 0){strcpy(unit_str, "Hz");}elseif(freq_unit == 1){strcpy(unit_str, "K");}else{strcpy(unit_str, "M");}if(edit_mode == 1 && freq_digit == 4 && !blink_state){u8g2_DrawHLine(u8g2, 90, 21, u8g2_GetStrWidth(u8g2, unit_str));}else{u8g2_DrawStr(u8g2, 90, 20, unit_str);}u8g2_SetFont(u8g2, u8g2_font_ncenB08_tf);u8g2_DrawStr(u8g2, 15, 35, "Min");uint8_t bar_width = (uint8_t)((current_vol / 127) * 90);u8g2_DrawRBox(u8g2, 25, 40, bar_width, 12, 3);u8g2_DrawRFrame(u8g2, 25, 40, 90, 12, 3);u8g2_DrawStr(u8g2, 100, 35, "Max");// 在滑条下方显示当前值u8g2_SetFont(u8g2, u8g2_font_ncenB08_tf);sprintf(vol_str, "%d", current_vol);uint8_t vol_num_width = u8g2_GetStrWidth(u8g2, vol_str);uint8_t vol_num_x = 25 + (90 - vol_num_width) / 2; // 居中显示u8g2_DrawStr(u8g2, vol_num_x, 65, vol_str);u8g2_SendBuffer(u8g2);}
GUI绘制中,计算各个显示位数,实现Fre:xxx.xKHZ这个格式的实现以及使用滑条显示MCP4017的档位。
KeyScan(&Userkey1,GPIOA,GPIO_PIN_3);KeyScan(&Userkey2,GPIOA,GPIO_PIN_9);int16_t encoder1_current = __HAL_TIM_GET_COUNTER(&htim4);int16_t encoder2_current = __HAL_TIM_GET_COUNTER(&htim3);int16_t encoder1_diff = -(encoder1_current - encoder1_last);int16_t encoder2_diff = -(encoder2_current - encoder2_last);if(edit_mode == 1){if(encoder1_diff != 0){encoder1_accum += encoder1_diff;if(encoder1_accum >= 4 || encoder1_accum <= -4){if(freq_digit < 4){if(freq_digit == 0){if(encoder1_accum > 0){freq_digits[0]++;if(freq_digits[0] > 9) freq_digits[0] = 0;}else{if(freq_digits[0] == 0) freq_digits[0] = 9;else freq_digits[0]--;}}elseif(freq_digit == 1){if(encoder1_accum > 0){freq_digits[1]++;if(freq_digits[1] > 9){freq_digits[1] = 0;if(freq_digits[0] < 9){freq_digits[0]++;}}}else{if(freq_digits[1] == 0){freq_digits[1] = 9;if(freq_digits[0] > 0){freq_digits[0]--;}}else{freq_digits[1]--;}}}elseif(freq_digit == 2){if(encoder1_accum > 0){freq_digits[2]++;if(freq_digits[2] > 9){freq_digits[2] = 0;if(freq_digits[1] < 9){freq_digits[1]++;}}}else{if(freq_digits[2] == 0){freq_digits[2] = 9;if(freq_digits[1] > 0){freq_digits[1]--;}}else{freq_digits[2]--;}}}elseif(freq_digit == 3){if(encoder1_accum > 0){freq_digits[3]++;if(freq_digits[3] > 9){freq_digits[3] = 0;if(freq_digits[2] < 9){freq_digits[2]++;}}}else{if(freq_digits[3] == 0){freq_digits[3] = 9;if(freq_digits[2] > 0){freq_digits[2]--;}}else{freq_digits[3]--;}}}// 只更新显示值,不立即设置频率和保存uint32_t display_freq = freq_digits[0] * 100 + freq_digits[1] * 10 + freq_digits[2];if(freq_unit == 0){current_freq = display_freq;}elseif(freq_unit == 1){current_freq = display_freq * 1000 + freq_digits[3] * 100;}elseif(freq_unit == 2){current_freq = display_freq * 1000000 + freq_digits[3] * 100000;}}else{if(encoder1_accum > 0){if(freq_unit < 2){freq_unit++;}}else{if(freq_unit > 0){freq_unit--;}}uint32_t display_freq = freq_digits[0] * 100 + freq_digits[1] * 10 + freq_digits[2];if(freq_unit == 0){current_freq = display_freq;}elseif(freq_unit == 1){current_freq = display_freq * 1000;}elseif(freq_unit == 2){current_freq = display_freq * 1000000;}}encoder1_last = encoder1_current;encoder1_accum = 0;}}if(encoder2_diff != 0){encoder2_accum += encoder2_diff;if(encoder2_accum >= 4){if(freq_digit < 4){freq_digit++;}encoder2_accum = 0;}elseif(encoder2_accum <= -4){if(freq_digit > 0){freq_digit--;}encoder2_accum = 0;}encoder2_last = encoder2_current;}}elseif(edit_mode == 2){if(encoder1_diff != 0){encoder1_accum += encoder1_diff;if(encoder1_accum >= 4 || encoder1_accum <= -4){if(encoder1_accum > 0){if(current_vol < 127){current_vol++;}}else{if(current_vol > 0){current_vol--;}}MCP4017_SetWiper(current_vol);save_flag = 1;encoder1_last = encoder1_current;encoder1_accum = 0;}}}if(Userkey1._haspress){Userkey1._haspress = 0;if(edit_mode == 1){uint32_t display_freq = freq_digits[0] * 100 + freq_digits[1] * 10 + freq_digits[2];if(freq_unit == 0){current_freq = display_freq;}elseif(freq_unit == 1){current_freq = display_freq * 1000 + freq_digits[3] * 100;}elseif(freq_unit == 2){current_freq = display_freq * 1000000 + freq_digits[3] * 100000;}AD9833_SetFrequency(current_freq);save_flag = 1;edit_mode = 0;}else{edit_mode = 1;}}if(Userkey2._haspress){Userkey2._haspress = 0;edit_mode = 2;}
按键检测中使用定时器无阻塞检测的方式,对编码器状态实现判断,并设置标记。
227