基于STM8的ADC0832采集及蓝牙通信系统

发布者:TranquilDreamer最新更新时间:2017-09-12 来源: eefocus关键字:STM8  ADC0832采集  蓝牙通信系统 手机看文章 扫描二维码
随时随地手机看文章

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


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

程序存储器:8K字节Flash;RAM: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.   

  3. #include "stm8s.h"  

  4. #include "stm8s_it.h"  

  5.   

  6. uint8_t HexTable[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};  

  7. uint8_t i=0;  

  8.   

  9. //串口UART1初始化  

  10. void Init_UART(void)  

  11. {  

  12.   //默认初始化  

  13.   UART1_DeInit();         

  14.   //设置波特率9600 8位数据 1位停止位 无校验  外部时钟不可用 模式接收发送  

  15.   UART1_Init((u32)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);  

  16.   //设置接收寄存器溢出中断  

  17.   UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);  

  18. }  

  19. //定时器TIM4初始化  

  20. void Init_Timer4(void)  

  21. {  

  22.   //1ms中断一次  

  23.   TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124);  

  24.   /* Clear TIM4 update flag */  

  25.   TIM4_ClearFlag(TIM4_FLAG_UPDATE);  

  26.   /* Enable update interrupt */  

  27.   TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);  

  28.   TIM4_Cmd(ENABLE);  

  29. }  

  30. //发送字节  

  31. void Send(uint8_t dat)  

  32. {  

  33.   //检查并等待发送寄存器是否为空  

  34.   while(( UART1_GetFlagStatus(UART1_FLAG_TXE)==RESET));  

  35.   //发送字节  

  36.   UART1_SendData8(dat);  

  37. }  

  38. //发送16位16进制  

  39. void UART1_mysend16hex(u16 dat)  

  40. {  

  41.     Send(HexTable[(dat>>12)&0x0f]);  

  42.     Send(HexTable[(dat>>8)&0x0f]);  

  43.     Send(HexTable[(dat>>4)&0x0f]);  

  44.     Send(HexTable[(dat)&0x0f]);  

  45. }  

  46. //发送8位16进制  

  47. void UART1_mysend8hex(uint8_t dat)  

  48. {  

  49.     Send(HexTable[(dat>>4)&0x0f]);  

  50.     Send(HexTable[(dat)&0x0f]);  

  51.     Send('U');  

  52. }  

  53. void main()  

  54. {  

  55.   //初始化  

  56.   Init_UART();  

  57.   Init_Timer4();  

  58.   //中断开启  

  59.   enableInterrupts();   

  60.   while(1)  

  61.   {  

  62.   }  

  63. }  

  64.   

  65. //这个必须加上 不然会报错 估计是库的要求  

  66.   

  67. #ifdef USE_FULL_ASSERT  

  68. void assert_failed(u8* file, u32 line)  

  69. {   

  70.   while (1)  

  71.   {  

  72.   }  

  73. }  

  74. #endif  



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

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

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

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

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

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


  1. stm8s_it.c程序:  

  2.   

  3. #include "stm8s_it.h"  

  4. #include "ADC0832.h"  

  5. extern uint8_t i;  

  6. uint8_t channel=1 ;  

  7.   

  8. //接收寄存器溢出中断  

  9. INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)  

  10.  {  

  11.     /* In order to detect unexpected events during development, 

  12.        it is recommended to set a breakpoint on the following instruction. 

  13. */  

  14. //下面是我做的安卓上位机发送过来的数据判断,这里可以改成自己想要的程序  

  15.   uint8_t tempData;  

  16.   tempData = UART1_ReceiveData8();  

  17.   if(tempData=='A')  

  18.   {  

  19.     channel = 0;  

  20.   }   

  21.   if(tempData=='Z')  

  22.   {  

  23.     channel = 1;  

  24.   }  

  25. //清除UART1中断标识符  

  26.     UART1_ClearITPendingBit(UART1_IT_RXNE);  

  27.  }  

  28.   

  29. //定时器4计数器溢出中断  

  30. INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)  

  31.  {  

  32.   /* In order to detect unexpected events during development, 

  33.      it is recommended to set a breakpoint on the following instruction. 

  34.   */  

  35.    //1*10m执行一次  

  36.    i++;  

  37.    if(i==10)  

  38.    {  

  39.     //进行ADC数模转换  

  40. //初始化ADC芯片,写入通道  

  41.     AD_init(channel);  

  42. u8 u8_adc1_value;  

  43. //进行数据读出  

  44. u8_adc1_value = AD_read();  

  45. //发送8位数据  

  46. UART1_mysend8hex(u8_adc1_value);  

  47. //清除UART1中断标识符  

  48.     UART1_ClearITPendingBit(UART1_IT_RXNE);  

  49.     i=0;  

  50.    }  

  51.    TIM4_ClearITPendingBit(TIM4_IT_UPDATE);  

  52.  }  


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

程序包括初始化STM8的GPIO,初始化ADC0832和读取ADC0832数据

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

附上时序图



  1. ADC0832.c程序:  

  2.   

  3. /********************************************** 

  4. 程序名称:ADC0832子程序 

  5. 作    者:devinzhang91 

  6. 时    间:2014.10.04 

  7. **********************************************/  

  8. #ifndef ADC0832_H  

  9. #define ADC0832_H  

  10. #include "stm8s.h"  

  11.   

  12. //端口设置  

  13. #define CLK_GPIO_PORT  (GPIOC)  

  14. #define CLK_GPIO_PINS  (GPIO_PIN_3)  

  15. #define DI_GPIO_PORT  (GPIOC)  

  16. #define DI_GPIO_PINS  (GPIO_PIN_4)  

  17. #define DO_GPIO_PORT  (GPIOC)  

  18. #define DO_GPIO_PINS  (GPIO_PIN_4)  

  19. #define CS_GPIO_PORT  (GPIOC)  

  20. #define CS_GPIO_PINS  (GPIO_PIN_1)  

  21.   

  22. /******************************************************** 

  23. 函数名称:void ioInit(void) 

  24. 函数作用:初始化GPIO 

  25. 参数说明:null 

  26. ********************************************************/  

  27. void ioInit(void)  

  28. {  

  29.   //全为输出模式  

  30.   GPIO_Init(CLK_GPIO_PORT, CLK_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);  

  31.   GPIO_Init(DI_GPIO_PORT, DI_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);  

  32.   GPIO_Init(DO_GPIO_PORT, DO_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);  

  33.   GPIO_Init(CS_GPIO_PORT, CS_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);  

  34. }  

  35.   

  36. /******************************************************** 

  37. 函数名称:void ioChange() 

  38. 函数作用:初始化GPIO 

  39. 参数说明:i=0,表示输出,i=1,表示输入 

  40. ********************************************************/  

  41. void ioChange(uchar i)  

  42. {  

  43.   if( i == 0)  

  44.     GPIO_Init(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);  

  45.   if( i == 1)  

  46.     GPIO_Init(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS, GPIO_MODE_IN_PU_NO_IT);  

  47. }  

  48.   

  49. /******************************************************** 

  50. 函数名称:void AD_init(uchar i) 

  51. 函数作用:初始化ADC0832 

  52. 参数说明:i=0,表示通道0,i=1,表示通道1 

  53. ********************************************************/  

  54. void AD_init(uchar i)   

  55. {  

  56.     ioInit();   //初始化io  

  57.     ioChange(0);  //作为输出  

  58.     GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿  

  59.     asm("nop");  

  60.     asm("nop");  

  61.     GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);       /*在第1 个时钟脉冲的下沉之前DI端必须是高电平,表示启始信号*/  

  62.     asm("nop");  

  63.     asm("nop");  

  64.     GPIO_WriteLow(CS_GPIO_PORT, (GPIO_Pin_TypeDef)CS_GPIO_PINS);  //使能ADC0832  

  65.     asm("nop");  

  66.     asm("nop");  

  67.     GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);  

  68.     asm("nop");  

  69.     asm("nop");  

  70.     GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿1   

  71.     asm("nop");  

  72.     asm("nop");         /*在第2、3个脉冲下沉之前DI端应输入2位数据用于选择通道功能*/  

  73.     if( i==0 )  

  74.       GPIO_WriteLow(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);  

  75.     if( i==1 )  

  76.       GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);  

  77.     asm("nop");  

  78.     asm("nop");  

  79.     GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);  

  80.     asm("nop");  

  81.     asm("nop");  

  82.     GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿2   

  83.     asm("nop");  

  84.     asm("nop");  

  85.     if( i==0 )  

  86.       GPIO_WriteLow(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);  

  87.     if( i==1 )  

  88.       GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);  

  89.     GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);  

  90.     asm("nop");  

  91.     asm("nop");  

  92.     GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿3   

  93.     asm("nop");  

  94.     asm("nop");  

  95. }  

  96. /******************************************************** 

  97. 函数名称:uchar AD_read() 

  98. 函数作用:读取ADC0832转换的数据 

  99. 参数说明:无 

  100. 函数返回:返回8位的数据 

  101. ********************************************************/  

  102. u8 AD_read()  

  103. {  

  104.     u8 temp1 = 0;  

  105.     u8 temp2 = 0;  

  106.     uchar i = 0;  

  107.     GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);  

  108.     asm("nop");  

  109.     asm("nop");  

  110.      ioChange(1); //作为输入  

  111.     for(i = 0; i < 8; i++)  

  112.     {  

  113.         GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);  

  114.         asm("nop");  

  115.         asm("nop");  

  116.         GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);   //形成下降沿  

  117.         asm("nop");  

  118.         asm("nop");  

  119.         temp1 = temp1 << 1;  

  120.         if(GPIO_ReadInputPin(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS) !=0)  

  121.           temp1 |= 0x01;  

  122.         else temp1 |= 0x00;  

  123.     }  

  124.       

  125.     for(i = 0; i < 8; i++)  

  126.    {  

  127.        temp2 = temp2>>1;  

  128.        if(GPIO_ReadInputPin(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS) !=0)  

  129.             temp2 = temp2|0x80;  

  130.        GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);  

  131.        asm("nop");  

  132.        asm("nop");  

  133.        GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);   //形成下降沿   

  134.        asm("nop");  

  135.        asm("nop");  

  136.     }  

  137.     GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);  

  138.     asm("nop");  

  139.     asm("nop");  

  140.     GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);  

  141.     asm("nop");  

  142.     asm("nop");  

  143.     GPIO_WriteHigh(CS_GPIO_PORT, (GPIO_Pin_TypeDef)CS_GPIO_PINS);  //使能ADC0832  

  144.     asm("nop");  

  145.     asm("nop");  

  146.          

  147.     if(temp1 == temp2)  

  148.       return temp1;  

  149.     else  

  150.       return 0;  

  151. }  

  152. #endif  



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


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


关键字:STM8  ADC0832采集  蓝牙通信系统 引用地址:基于STM8的ADC0832采集及蓝牙通信系统

上一篇:stm8s开发(二) GPIO的使用:点亮LED!
下一篇:stm8s开发(一) 使用IAR新建工程

推荐阅读最新更新时间:2024-03-16 15:36

STM8将库函数移植为寄存器方法
在使用使用STM32单片机的时候,喜欢使用库函数,由于stm32的寄存器太多了,如果直接使用寄存器的话,设置起来太麻烦了,而且stm32单片机速度快,容量大,使用寄存器要额提高不了多少效率。 对于STM8单片机来说使用寄存器还是很有必要的,本身stm8单片机的速度相比于stm32就会慢很多,同时芯片容量也比较小,使用库函数的话,比较占用空间,导致系统稍微大一点,芯片容量就不够用,所以在stm8单片机上,使用比较多的就是寄存器,stm8的寄存器也比较少,设置起来也比较简单。 但是好多stm8单片机的例程都是库函数版的,那么如何将库函数版的代码移植为寄存器版的呢? 这里使用LED闪烁的库函数代码来说明 打开一个LED库
[单片机]
<font color='red'>STM8</font>将库函数移植为寄存器方法
基于STM8的LCD界面点阵字库显示
本方案主控采用STM8S207C8T6,1.7寸128*64LCD显示屏,LCD驱动芯片采用UC1701(可兼容ST7565),字库显示采用高通GT20L16S1Y字库芯片, 以实现LCD界面上的显示。 以下分别是STM8S207C8T6,UC1701和GT20L16S1Y在原理图中的模块电路。 原理图是依据datasheet中的阐述所绘制,其中主控电路是使用了stm8s207c8t6芯片绘制的最小系统,显示屏部分是根据设置BM0和BM1来选择总线模式绘制的电路。这里我使用了SPI总线模式。而字库芯片本身就是SPI总线模式通信,直接根据规格书的电路例子使用即可。完成了电路部分,知道了总线模式,再结合数据手册就可以
[单片机]
基于<font color='red'>STM8</font>的LCD界面点阵字库显示
STM8单片机串口驱动的深度解析
串口是单片机最重要的外设之一,在很多项目开发中都有应用,Lora模块的外部通讯方式就是串口。 本节简单的和大家解析一下串口通讯及驱动代码的编程。 STM8L101F3单片机支持一路串口通讯。我们先看一下Lora模块的硬件接口,如下图所示: 串口的硬件接口是PC2 和PC3两个脚位。 下面开始讲解软件部分,这块我们无际单片机编程也有这个项目全部视频教程,下面是文字版。 软件驱动 STM8打开标准库文件夹,打开串口USART例程: 2.如上图所示,是标准库中串口通讯的的例程,并选择第一个例程。 3.我们按照之前的方式,把USART_HyperTerminalInterrupt文件复制到ProjectSTM8
[单片机]
<font color='red'>STM8</font>单片机串口驱动的深度解析
STM8 beCAN工作模式
STM8 beCAN工作模式 beCAN有3个主要的工作模式:初始化模式、正常模式和睡眠模式。 在硬件复位后,beCAN工作在睡眠模式以减少功耗。软件通过对CAN_MCR寄存器的INRQ或SLEEP置'1',可以请求beCAN进入初始化或睡眠模式。一旦进入了初始化或睡眠模式,beCAN就对CAN_MSR寄存器的INAK或SLAK位置'1'来进行确认。当INAK和SLAK位都为'0'时,beCAN就处于正常模式。在进入正常模式前,beCAN必须跟CAN总线取得同步;为取得同步,beCAN要等待直到CAN总线处于空闲状态,即在CANRX引脚上监测到11个连续的隐性位。 初始化模式 软
[单片机]
<font color='red'>STM8</font> beCAN工作模式
STM8单片机工程师之路二-与或非操作位
与或非操作的问题 PE_ODR &= 0XFE; //第0位清零,输出低电平 PD_ODR &= 0XF7; //第3位清零,输出低电平 我之前不知道为什么这样写! 现在来解释一下&=0XFE=1111 1110,也就是再用&=的时候,高7位待定, 第0位就是0这是一定的。 那么&0XF7=1111 0111 同理第3位一定是0。 &是什么作用呢? 让某一位清零,也就是最低位清零,而其他位保持不变; PE_ODR |= 0X01; //第0位置位,输出高电平 PD_ODR |= 0X08; //第3位置位,输出高电平 解释:|=0X01=0000 0001 这个是|=操作,所以高八位待定不变,第0位必定置1 同理:|= 0
[单片机]
STM8问题总结
1、Failed to write chunk with size 128 at address 0x8000: SWIM PROG error : Attempt to write to protected area STM8芯片写保护了,需要解除一下写保护,使用STVP这个软件 ,打开之后选择OPTION BYTE 然后点击图标 即可。
[单片机]
<font color='red'>STM8</font>问题总结
STM8定时器初始化和GPIO初始化顺序导致GPIO动作不正确
现象 用定时器TIM4定时翻转GPIO用低电平灌电流驱动LED闪烁的简单测试程序不能正常执行。LED灯不闪烁,debug查看GPIO口却是正确的被翻转了。测试IO口电压不对。 问题代码 void main(void) { // 系统时钟不分频(内部16MHz) CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); // TIM4进行128分频,同时设置溢出上限值保证1ms一次中断 TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124); // 开TIM4更新事件中断 TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
[单片机]
STM8单片机通过PWM触发ADC同步采样
  在做数字开关电源开发过程中使用最多的就是PWM功能和ADC采样功能。ADC采样时采样的时间点很重要,必须在PWM输出高电平的时候取采样,这样采样出来的数据才是最准确的。在STM8单片机中,可以通过定时器的TRG信号去触发ADC采样,这样就可以将PWM波形的输出和ADC采样结合在一起了。   下面就演示一下,如何在输出PWM波的过程中触发ADC采样。   首先看ADC的初始化代码。 #include adc.h #include main.h #include led.h u16 DATAH = 0; //ADC转换值高8位 u16 DATAL = 0; //ADC
[单片机]
<font color='red'>STM8</font>单片机通过PWM触发ADC同步采样
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved