当前位置:   article > 正文

B001-Atmega16-数码管_atmega16单片机编程数码管显示数字

atmega16单片机编程数码管显示数字

一步步完成数码管

主要内容:
第一步:产生1ms的时基
第二步:静态显示
第三步:动态扫描
第四步:余晖 重影
第五步:带消息机制的任务函数
第六步:按指定进制显示


-------------------------------------------------------------------------------------------------------------------------------------
开发环境:AVR Studio 4.19 + avr-toolchain-installer-3.4.1.1195-win32.win32.x86
芯片型号:ATmega16
芯片主频:8MHz

-------------------------------------------------------------------------------------------------------------------------------------

第一步: 产生1ms的时基

说明:
1、使用定时器0的 CTC中断产生 1ms的时基信号, CTC模式下时自动重装初值、比较方便。
2、使用 OCF0中断、不需要 OC0引脚输出波形。

代码:

Drv_Timer.h中的相关定义:

  1. // -------------------
  2. // 定时器中断模式
  3. typedef enum
  4. {
  5. INT_MODE_TOV = 0,
  6. INT_MODE_OCF = 1,
  7. INT_MODE_ICF = 2,
  8. INT_MODE_OCF1A = 3,
  9. INT_MODE_OCF1B = 4
  10. } TIMER_INT_MODE;
  11. // 定时器比较匹配引脚输出模式
  12. typedef enum
  13. {
  14. COM_MODE_NONE = 0,
  15. COM_MODE_TOGGLE = 1,
  16. COM_MODE_CLEAR = 2,
  17. COM_MODE_SET = 3,
  18. } TIMER_COM_MODE;
  19. // 定时器0
  20. typedef enum
  21. {
  22. T0_WGM_NOMAL = 0,
  23. T0_WGM_PHASE_PWM = 1,
  24. T0_WGM_CTC = 2,
  25. T0_WGM_FAST_PWM = 3,
  26. T0_CLK_SOURCE_NONE = 0,
  27. T0_CLK_SOURCE_CLK_1 = 1,
  28. T0_CLK_SOURCE_CLK_8 = 2,
  29. T0_CLK_SOURCE_CLK_64 = 3,
  30. T0_CLK_SOURCE_CLK_256 = 4,
  31. T0_CLK_SOURCE_CLK_1024 = 5,
  32. T0_CLK_SOURCE_T0_FALL = 6,
  33. T0_CLK_SOURCE_T0_RAISE = 7
  34. } TIMER0_MODE;
Drv_Timer.c中的操作函数:
  1. // ==========================================================================================================
  2. // TIMER0 初始化
  3. //
  4. // 参数:wave_mode 工作模式/波形产生模式选择
  5. // OC_mode 比较匹配/PWM输出模式选择
  6. // clk_source 时钟源和预分频选择
  7. //
  8. // 写TCCR0时需要清除bit7=FOC0
  9. //
  10. // 定时器溢出周期 T = ((1.0 / 8000000) * 1000000) * clk_source * 256 ( @ 8MHz )
  11. // ==========================================================================================================
  12. void Drv_Timer0_init(const uint8_t wave_mode, const uint8_t com_mode, const uint8_t clk_source)
  13. {
  14. uint8_t wgm00,wgm01;
  15. wgm00 = wave_mode & 0x01;
  16. wgm01 = (wave_mode & 0x02) >> 1;
  17. // 写TCCR0时需要将bit7=FOC0清0
  18. TCCR0 = (wgm00 << 6)| // 工作模式/波形产生模式选择
  19. (wgm01 << 3)|
  20. ((com_mode & 0x03) << 4)| // 比较匹配/PWM输出模式选择
  21. ((clk_source & 0x07) << 0); // 时钟源和预分频选择
  22. }
  23. // ==========================================================================================================
  24. // TIMER0 中断使能
  25. //
  26. // 参数:int_mode = INT_MODE_TOV 或 INT_MODE_OCF 或 INT_MODE_ICF
  27. // enable = ENABLE 或 DISABLE
  28. //
  29. // 说明:
  30. // 1、OC0引脚要先配置成比较匹配引脚、再修改数据方向寄存器DDB3
  31. // 2、可以单独使能/禁止一种模式的中断
  32. //
  33. // ==========================================================================================================
  34. void Drv_Timer0_INT_Enable(const uint8_t int_mode, const uint8_t enable)
  35. {
  36. if(INT_MODE_TOV == int_mode)
  37. {
  38. if(DISABLE == enable)
  39. {
  40. TIMSK &= ~(1 << TOIE0);
  41. }
  42. else
  43. {
  44. TIMSK |= (1 << TOIE0);
  45. }
  46. TIFR |= (1 << TOV0);
  47. return ;
  48. }
  49. if(INT_MODE_OCF == int_mode)
  50. {
  51. if(DISABLE == enable)
  52. {
  53. TIMSK &= ~(1 << OCIE0);
  54. }
  55. else
  56. {
  57. TIMSK |= (1 << OCIE0);
  58. }
  59. TIFR |= (1 << OCF0);
  60. }
  61. }
  62. // ==========================================================================================================
  63. // 设置TCNT0和OCR0的值
  64. //
  65. // (1). 在比较匹配下、OCR0需要在TCNT0被设置之后设置
  66. // ==========================================================================================================
  67. void Drv_Timer0_set_TCNT0_OCR0(const uint8_t tcnt0, const uint8_t ocr0)
  68. {
  69. TCNT0 = tcnt0;
  70. OCR0 = ocr0;
  71. }
sys_timer.c中设置定时器0,并在OCF0中断中使用PA1测试定时时间:
  1. #include <avr/interrupt.h>
  2. #include "Drv_Timer.h"
  3. #include "sys_timer.h"
  4. // ==========================================================================================================
  5. // 系统任务定时器
  6. //
  7. // (1). 使用Timer0产生1ms的时标
  8. // 定时周期 T = ((1.0/8000000)*1000000)*64*(124+1) = 1000us = 1ms
  9. //
  10. // ==========================================================================================================
  11. void sys_timer_init(void)
  12. {
  13. // 定时器0初始化:CTC模式、OC0引脚不连接、64预分频
  14. Drv_Timer0_init(T0_WGM_CTC, COM_MODE_NONE, T0_CLK_SOURCE_CLK_64);
  15. // 设置初值:TCNT0=0、OCR0=122
  16. Drv_Timer0_set_TCNT0_OCR0(0, 122);
  17. // 使能OCF0中断
  18. Drv_Timer0_INT_Enable(INT_MODE_OCF, ENABLE);
  19. }
  20. // ==========================================================================================================
  21. // 系统定时器中断
  22. //
  23. // (1). 使用Timer0的CTC中断调度各个任务
  24. //
  25. // ==========================================================================================================
  26. ISR(TIMER0_COMP_vect)
  27. {
  28. PORTA ^= (1 << PA1); // 使用PA1测试定时周期
  29. }
main.c中完成初始化,并设置IO:
  1. // ==========================================================================================================
  2. // 主函数
  3. // ==========================================================================================================
  4. #include <avr/io.h>
  5. #include "Drv_Timer.h"
  6. #include "system.h"
  7. #include "sys_timer.h"
  8. #include "config.h"
  9. // ==========================================================================================================
  10. // main函数
  11. // ==========================================================================================================
  12. int main(void)
  13. {
  14. // ---------
  15. // 关全局中断
  16. cli();
  17. // 系统初始化 ( 包含sys_timer_init() )
  18. sys_init();
  19. DDRA |= (1 << DDA0) | (1 << DDA1);
  20. PORTA &= ~((1 << PA0 ) | (1 << PA1 ));
  21. // OC0/PB3初始化为输出0
  22. DDRB |= (1 << DDB3);
  23. PORTB &= ~((1 << PB3 ));
  24. // 开全局中断
  25. sei();
  26. // ---------
  27. while(1)
  28. {
  29. }
  30. return 0;
  31. }

测试结果:

示波器输出如下:

1、 PA1引脚输出方波,周期是 2*1.0ms,引脚电平每隔 1.0ms翻转一次。
      使用 OCR0=124、计算得到精确的 1.0ms,但进入中断函数是需要花费时间的。
      所以这里使用稍小的 OCR0=122,让从中断产生到进入中断函数为止的时间更精确为 1.0ms
      有些计时功能会积累时基的误差、越到后面积累的误差越大,所以这里能精确就尽量做的精确些。
      到此、 1.0ms定时完成。
2、 OC0引脚没有波形输出,我们也不需要用到这个引脚,就让他保持普通 IO的特性吧。


-------------------------------------------------------------------------------------------------------------------------------------

第二步: 静态显示

说明:

1、这一步需要根据电路图、在指定的数码管上显示指定的符号。

1、数码管驱动电路图:


电路中使用的是共阴极数码管:
1个数码管有8个LED,称为8段数码管

</

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/848874
推荐阅读
相关标签
  

闽ICP备14008679号