当前位置:   article > 正文

基于STM8的ADC0832采集及蓝牙通信系统_adc0832与stm32怎么连接

adc0832与stm32怎么连接

为了方便大家学习,工程已经打包上传,http://download.csdn.net/detail/devintt/8029389


最近在淘宝逛的时候发现了一款单片机,STM8。相比之前一直使用的也是8位的AVR相比,感觉STM8更为强大,芯片特点如下:


内核:具有3级流水线的哈佛结构、扩展指令集

程序存储器8K字节FlashRAM:1K字节

数据存储器640 字节真正的数据EEPROM;可达30万次擦写

更重要的一点就是STM8系列若使用库编程的话,可以方便的不同芯片的程序移植。甚至可以方便的移植到STM32上面,大大减轻了更新硬件的重写程序的工作量。

 

ADC0832 为8位分辨率A/D转换芯片,其最高分辨可达256级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在0~5V之间。芯片转换时间仅为32μS,据有双数据输出可作为数据校验,以减少数据误差,转换速度快且稳定性能强。独立的芯片使能输入,使多器件挂接和处理器控制变的更加方便。通过DI 数据输入端,可以轻易的实现通道功能的选择。(简述和图片均来之百度百科)


本文适合STM8控制ADC0832,程序是使用库编程,编译工具IAR。其实STM8也自带ADC转换模块了......

     本程序还包括蓝牙串口通信,方便将得到数据从串口输出,我是编写了安卓上位机的app,方便在安卓上面显示图像。

程序还是用了定时器TIM4,确保每次采样的间隔大致相等,对之后的数据处理提供了基础。

 

先介绍核心mian.c文件,主要功能是初始化串口UART1,定时器TIMER4,还有一个发送16进制的函数。其中发送完数据再发送一个字符’U’作为一个数据的结束(你也可以自己定义)。这里说说为什么要选用16进制,而不是10进制,STM8速度有限,为了减少单指令操作,程序用了移位操作,这样可得到16进制每位数值,在发送到安卓上位机,上位机运算速度快,再转化成10进制,这样可以资源合理分配。

  1. main.c程序:
  2. #include "stm8s.h"
  3. #include "stm8s_it.h"
  4. uint8_t HexTable[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  5. uint8_t i=0;
  6. //串口UART1初始化
  7. void Init_UART(void)
  8. {
  9. //默认初始化
  10. UART1_DeInit();
  11. //设置波特率9600 8位数据 1位停止位 无校验 外部时钟不可用 模式接收发送
  12. UART1_Init((u32)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
  13. //设置接收寄存器溢出中断
  14. UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);
  15. }
  16. //定时器TIM4初始化
  17. void Init_Timer4(void)
  18. {
  19. //1ms中断一次
  20. TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124);
  21. /* Clear TIM4 update flag */
  22. TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  23. /* Enable update interrupt */
  24. TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
  25. TIM4_Cmd(ENABLE);
  26. }
  27. //发送字节
  28. void Send(uint8_t dat)
  29. {
  30. //检查并等待发送寄存器是否为空
  31. while(( UART1_GetFlagStatus(UART1_FLAG_TXE)==RESET));
  32. //发送字节
  33. UART1_SendData8(dat);
  34. }
  35. //发送16位16进制
  36. void UART1_mysend16hex(u16 dat)
  37. {
  38. Send(HexTable[(dat>>12)&0x0f]);
  39. Send(HexTable[(dat>>8)&0x0f]);
  40. Send(HexTable[(dat>>4)&0x0f]);
  41. Send(HexTable[(dat)&0x0f]);
  42. }
  43. //发送8位16进制
  44. void UART1_mysend8hex(uint8_t dat)
  45. {
  46. Send(HexTable[(dat>>4)&0x0f]);
  47. Send(HexTable[(dat)&0x0f]);
  48. Send('U');
  49. }
  50. void main()
  51. {
  52. //初始化
  53. Init_UART();
  54. Init_Timer4();
  55. //中断开启
  56. enableInterrupts();
  57. while(1)
  58. {
  59. }
  60. }
  61. //这个必须加上 不然会报错 估计是库的要求
  62. #ifdef USE_FULL_ASSERT
  63. void assert_failed(u8* file, u32 line)
  64. {
  65. while (1)
  66. {
  67. }
  68. }
  69. #endif


接下来说说中断函数表stm8s_it.c

其中只要选用两个中断函数就可以了:

INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18) 接收寄存器溢出中断

里面添加安卓上位机发送过来的数据的处理程序,我这里写的是ADC0832通道选择的判断。

INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23) 定时器4计数器溢出中断

里面添加初始化ADC0832ADC0832数据读取并UART1发送到安卓上位机。

  1. stm8s_it.c程序:
  2. #include "stm8s_it.h"
  3. #include "ADC0832.h"
  4. extern uint8_t i;
  5. uint8_t channel=1 ;
  6. //接收寄存器溢出中断
  7. INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
  8. {
  9. /* In order to detect unexpected events during development,
  10. it is recommended to set a breakpoint on the following instruction.
  11. */
  12. //下面是我做的安卓上位机发送过来的数据判断,这里可以改成自己想要的程序
  13. uint8_t tempData;
  14. tempData = UART1_ReceiveData8();
  15. if(tempData=='A')
  16. {
  17. channel = 0;
  18. }
  19. if(tempData=='Z')
  20. {
  21. channel = 1;
  22. }
  23. //清除UART1中断标识符
  24. UART1_ClearITPendingBit(UART1_IT_RXNE);
  25. }
  26. //定时器4计数器溢出中断
  27. INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)
  28. {
  29. /* In order to detect unexpected events during development,
  30. it is recommended to set a breakpoint on the following instruction.
  31. */
  32. //1*10m执行一次
  33. i++;
  34. if(i==10)
  35. {
  36. //进行ADC数模转换
  37. //初始化ADC芯片,写入通道
  38. AD_init(channel);
  39. u8 u8_adc1_value;
  40. //进行数据读出
  41. u8_adc1_value = AD_read();
  42. //发送8位数据
  43. UART1_mysend8hex(u8_adc1_value);
  44. //清除UART1中断标识符
  45. UART1_ClearITPendingBit(UART1_IT_RXNE);
  46. i=0;
  47. }
  48. TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
  49. }

这里说说ADC0832的操作函数:ADC0832.c

程序包括初始化STM8GPIO,初始化ADC0832和读取ADC0832数据

主要是DODI端口复用的问题,由于STM8端口作为输入输出,需要重新初始化GPIO,所以比一般51单片机的程序要复杂一点。最后读取数据先是从高位读出,再低位读出,进行校验,相同数值再输出。

附上时序图


 

  1. ADC0832.c程序:
  2. /**********************************************
  3. 程序名称:ADC0832子程序
  4. 作 者:devinzhang91
  5. 时 间:2014.10.04
  6. **********************************************/
  7. #ifndef ADC0832_H
  8. #define ADC0832_H
  9. #include "stm8s.h"
  10. //端口设置
  11. #define CLK_GPIO_PORT (GPIOC)
  12. #define CLK_GPIO_PINS (GPIO_PIN_3)
  13. #define DI_GPIO_PORT (GPIOC)
  14. #define DI_GPIO_PINS (GPIO_PIN_4)
  15. #define DO_GPIO_PORT (GPIOC)
  16. #define DO_GPIO_PINS (GPIO_PIN_4)
  17. #define CS_GPIO_PORT (GPIOC)
  18. #define CS_GPIO_PINS (GPIO_PIN_1)
  19. /********************************************************
  20. 函数名称:void ioInit(void)
  21. 函数作用:初始化GPIO
  22. 参数说明:null
  23. ********************************************************/
  24. void ioInit(void)
  25. {
  26. //全为输出模式
  27. GPIO_Init(CLK_GPIO_PORT, CLK_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  28. GPIO_Init(DI_GPIO_PORT, DI_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  29. GPIO_Init(DO_GPIO_PORT, DO_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  30. GPIO_Init(CS_GPIO_PORT, CS_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  31. }
  32. /********************************************************
  33. 函数名称:void ioChange()
  34. 函数作用:初始化GPIO
  35. 参数说明:i=0,表示输出,i=1,表示输入
  36. ********************************************************/
  37. void ioChange(uchar i)
  38. {
  39. if( i == 0)
  40. GPIO_Init(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  41. if( i == 1)
  42. GPIO_Init(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS, GPIO_MODE_IN_PU_NO_IT);
  43. }
  44. /********************************************************
  45. 函数名称:void AD_init(uchar i)
  46. 函数作用:初始化ADC0832
  47. 参数说明:i=0,表示通道0,i=1,表示通道1
  48. ********************************************************/
  49. void AD_init(uchar i)
  50. {
  51. ioInit(); //初始化io
  52. ioChange(0); //作为输出
  53. GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS); //形成下降沿
  54. asm("nop");
  55. asm("nop");
  56. GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS); /*在第1 个时钟脉冲的下沉之前DI端必须是高电平,表示启始信号*/
  57. asm("nop");
  58. asm("nop");
  59. GPIO_WriteLow(CS_GPIO_PORT, (GPIO_Pin_TypeDef)CS_GPIO_PINS); //使能ADC0832
  60. asm("nop");
  61. asm("nop");
  62. GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
  63. asm("nop");
  64. asm("nop");
  65. GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS); //形成下降沿1
  66. asm("nop");
  67. asm("nop"); /*在第2、3个脉冲下沉之前DI端应输入2位数据用于选择通道功能*/
  68. if( i==0 )
  69. GPIO_WriteLow(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
  70. if( i==1 )
  71. GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
  72. asm("nop");
  73. asm("nop");
  74. GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
  75. asm("nop");
  76. asm("nop");
  77. GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS); //形成下降沿2
  78. asm("nop");
  79. asm("nop");
  80. if( i==0 )
  81. GPIO_WriteLow(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
  82. if( i==1 )
  83. GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
  84. GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
  85. asm("nop");
  86. asm("nop");
  87. GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS); //形成下降沿3
  88. asm("nop");
  89. asm("nop");
  90. }
  91. /********************************************************
  92. 函数名称:uchar AD_read()
  93. 函数作用:读取ADC0832转换的数据
  94. 参数说明:无
  95. 函数返回:返回8位的数据
  96. ********************************************************/
  97. u8 AD_read()
  98. {
  99. u8 temp1 = 0;
  100. u8 temp2 = 0;
  101. uchar i = 0;
  102. GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
  103. asm("nop");
  104. asm("nop");
  105. ioChange(1); //作为输入
  106. for(i = 0; i < 8; i++)
  107. {
  108. GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
  109. asm("nop");
  110. asm("nop");
  111. GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS); //形成下降沿
  112. asm("nop");
  113. asm("nop");
  114. temp1 = temp1 << 1;
  115. if(GPIO_ReadInputPin(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS) !=0)
  116. temp1 |= 0x01;
  117. else temp1 |= 0x00;
  118. }
  119. for(i = 0; i < 8; i++)
  120. {
  121. temp2 = temp2>>1;
  122. if(GPIO_ReadInputPin(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS) !=0)
  123. temp2 = temp2|0x80;
  124. GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
  125. asm("nop");
  126. asm("nop");
  127. GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS); //形成下降沿
  128. asm("nop");
  129. asm("nop");
  130. }
  131. GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
  132. asm("nop");
  133. asm("nop");
  134. GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
  135. asm("nop");
  136. asm("nop");
  137. GPIO_WriteHigh(CS_GPIO_PORT, (GPIO_Pin_TypeDef)CS_GPIO_PINS); //使能ADC0832
  138. asm("nop");
  139. asm("nop");
  140. if(temp1 == temp2)
  141. return temp1;
  142. else
  143. return 0;
  144. }
  145. #endif

再说说安卓上位机,一个简单蓝牙接收的apk,用于实时画图,可以显示和画出一段时间内的STM8采样的数值,从后台接收数据,发送消息至进程更新UI


为了方便大家学习,工程已经打包上传,http://download.csdn.net/detail/devintt/8029389




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

闽ICP备14008679号