文章目录
一、数据采集系统
1.题目要求
利用单片机设计一个多通道的数据采集系统,该系统可以实现对8路单端模拟电压、2路模拟输出,8路开关量的采集,其中每一路电压范围为0-3.3V。
可以通过按键来切换数据采集模式,可以将采集的数据通过RS232打印出来。
2.思路
如果是选择用51单片机来做的话,因为51单片机不包含内置的模数转换器(ADC)或数字模拟转换器(DAC)功能。如果你要使用ADC功能来进行模拟信号的采集,你需要通过外部连接ADC芯片和DAC芯片来实现,比较麻烦,所以我打算直接用STM32来做。
打算用51单片机来做的朋友,可以看看PCF8591芯片,它是一款8bit CMOS的AD/DA芯片,它具有4个模拟输入、1个模拟输出和1个串行IIC总线接口。PCF8591的3个地址引脚A0,A1和A2可以用于硬件地址编程,允许在同个IIC总线上接入8个PCF8591器件,而无需额外的硬件。可以看下我的另外一篇文章基于51单片机的AD/DA转换的串口通信proteus仿真(附源码)
最后弄8路ADC通道采集电压,2路DAC电压模拟输出,8路按键数字量输出,以及用3个按键来控制模式的选择即可,为了方便展示,再弄个OLED显示屏显示当前模式,数据直接输出在模拟终端或串口助手上。(想法挺美好,下面仿真的时候就知道DAC不起作用,还是得用上老朋友PCF8591来进行DAC输出电压)
3.仿真图
3.1 仿真图
这里为什么明明STM32有DAC外设,我还用PCF8591来进行DAC输出呢?
是因为我发现我写了DAC程序,但是不起作用,没有电压输出,我猜测可能是仿真中的STM32芯片没有集成DAC外设,当然也有可能是我写错了。
这里就不弄2路DAC输出了,弄一路看看效果把。
3.2 仿真图简单说明
主控芯片:STM32F103C8
HICK:64MHZ
Systick: 1ms
测试Led:PC13
Uart1:9600(PA9:tx1,PA10:rx1)
OLED显示屏:SCL(PB14),SDA(PB15)
ADC:
ADC1(PA0)
ADC2(PA1)
ADC3(PA2)
ADC4(PA3)
ADC5(PA6)
ADC6(PA7)
ADC7(PB0)
ADC8(PB1)
DAC:SCL1(PA11),SDA1(PA12)
KEY按键:
KEY_MODE1(PB3)
KEY_MODE2(PB4)
KEY_MODE3(PB5)
KEY1(PB6)
KEY2(PB7)
KEY3(PB8)
KEY4(PB9)
KEY5(PB10)
KEY6(PB11)
KEY7(PB12)
KEY8(PB13)
3.3 仿真图简单演示
初始状态
ADC模式
DAC模式
数字量模式
串口设置模式
*MODE1
*MODE2
*MODE3
4.仿真程序
4.1 程序说明
RS232串口协议
模式切换指令 *MODEH
H为0:初始模式
H为1:8路单端模拟电压输出模式
H为2:1路模拟输出模式
H为3:8路开关量输出模式
串口配置
4.2 主函数
/* Includes ------------------------------------------------------------------*/
#include "Drv_UserSystem.h"
/**
* @brief main function.
* @param none
* @retval none
*/
int main(void)
{
UserSystemInit();//用户配置初始化
while (1)
{
if (stSysTime.flg._10ms + TEN_MILLISECOND < Time_millis()) //10ms
{
stSysTime.flg._10ms = Time_millis();
Key_Scan();//按键扫描
OLED_Handel();//OLED显示
}
if (stSysTime.flg._50ms + FIFTY_MILLISECOND < Time_millis()) //50ms
{
stSysTime.flg._50ms = Time_millis();
}
if (stSysTime.flg._100ms + BEST_MILLISECOND < Time_millis()) //100ms
{
stSysTime.flg._100ms = Time_millis();
Receive_data_Handel();//数据接收判断
IWDG_ReloadCounter();//清开门狗
}
if (stSysTime.flg._1s + THOUSAND_MILLISECOND < Time_millis()) //1s
{
stSysTime.flg._1s = Time_millis();
ADC_Scan();//ADC扫描
DAC_Scan();//DAC输出
Led_Flicker();//灯光闪烁
}
}
}
4.3 ADC采集
ADC_FLAG值一开始不为1是因为发现刚上电仿真ADC采集的数据不准,要舍弃一段时间的数据,等到ADC稳定下来再去采集。
另外delay_syms延时是确保每次ADC都转换完成,不加应该也可以的。
/*******************************************************************************
* 函数名:ADC_Scan
* 描述 :ADC扫描
* 输入 :void
* 输出 :void
* 调用 :1s
* 备注 :
*******************************************************************************/
void ADC_Scan(void)
{
if((show_mode == 1) && (ADC_FLAG))
{
ADC_FLAG--;
ADC1_DATA_Init();
ADC1_Value = Read_AdC_Value(ADC_Channel_0);
delay_syms(10);
ADC2_DATA_Init();
ADC2_Value = Read_AdC_Value(ADC_Channel_1);
delay_syms(10);
ADC3_DATA_Init();
ADC3_Value = Read_AdC_Value(ADC_Channel_2);
delay_syms(10);
ADC4_DATA_Init();
ADC4_Value = Read_AdC_Value(ADC_Channel_3);
delay_syms(10);
ADC5_DATA_Init();
ADC5_Value = Read_AdC_Value(ADC_Channel_6);
delay_syms(10);
ADC6_DATA_Init();
ADC6_Value = Read_AdC_Value(ADC_Channel_7);
delay_syms(10);
ADC7_DATA_Init();
ADC7_Value = Read_AdC_Value(ADC_Channel_8);
delay_syms(10);
ADC8_DATA_Init();
ADC8_Value = Read_AdC_Value(ADC_Channel_9);
delay_syms(10);
if(!ADC_FLAG)
{
printf("ADC1_Value=%d\r\n",ADC1_Value);
printf("ADC2_Value=%d\r\n",ADC2_Value);
printf("ADC3_Value=%d\r\n",ADC3_Value);
printf("ADC4_Value=%d\r\n",ADC4_Value);
printf("ADC5_Value=%d\r\n",ADC5_Value);
printf("ADC6_Value=%d\r\n",ADC6_Value);
printf("ADC7_Value=%d\r\n",ADC7_Value);
printf("ADC8_Value=%d\r\n",ADC8_Value);
}
}
}
4.4 DAC输出
/*******************************************************************
DAC 变换, 转化函数
*******************************************************************/
uint8_t DACconversion(uint8_t sla,uint8_t c,uint8_t Val)
{
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(c); //发送控制字节
if(ack==0)return(0);
SendByte(Val); //发送DAC的数值
if(ack==0)return(0);
Stop_I2c(); //结束总线
return(1);
}
/*******************************************************************************
* 函数名:DAC_Scan
* 描述 :DAC输出
* 输入 :void
* 输出 :void
* 调用 :1s
* 备注 :
*******************************************************************************/
void DAC_Scan(void)
{
if((show_mode == 2) && (DAC_FLAG))
{
DAC_FLAG = 0;
DACconversion(PCF8591,0x40, DAC_value);
printf("DAC_Value=%d\r\n",DAC_value);
}
}
4.5 开关量输出
if((show_mode == 3) && (KEY_FLAG))
{
KEY_FLAG = 0;
printf("KEY1 = %d\r\n",KeyState.value1);
printf("KEY2 = %d\r\n",KeyState.value2);
printf("KEY3 = %d\r\n",KeyState.value3);
printf("KEY4 = %d\r\n",KeyState.value4);
printf("KEY5 = %d\r\n",KeyState.value5);
printf("KEY6 = %d\r\n",KeyState.value6);
printf("KEY7 = %d\r\n",KeyState.value7);
printf("KEY8 = %d\r\n",KeyState.value8);
}
if(show_mode == 3)
{
if(Key1_IN_Read() == 0)//key1
{
KeyState.value1 = 1;
if(!KeyState.Press1)
{
printf("KEY1 = %d\r\n",KeyState.value1);
}
KeyState.Press1 = 1;
}
else
{
if(KeyState.value1)
{
KeyState.value1= 0;
printf("KEY1 = %d\r\n",KeyState.value1);
}
KeyState.Press1 = 0;
}
if(Key2_IN_Read() == 0)//key2
{
KeyState.value2 = 1;
if(!KeyState.Press2)
{
printf("KEY2 = %d\r\n",KeyState.value2);
}
KeyState.Press2 = 1;
}
else
{
if(KeyState.value2)
{
KeyState.value2= 0;
printf("KEY2 = %d\r\n",KeyState.value2);
}
KeyState.Press2 = 0;
}
if(Key3_IN_Read() == 0)//key3
{
KeyState.value3 = 1;
if(!KeyState.Press3)
{
printf("KEY3 = %d\r\n",KeyState.value3);
}
KeyState.Press3 = 1;
}
else
{
if(KeyState.value3)
{
KeyState.value3= 0;
printf("KEY3 = %d\r\n",KeyState.value3);
}
KeyState.Press3 = 0;
}
if(Key4_IN_Read() == 0)//key4
{
KeyState.value4 = 1;
if(!KeyState.Press4)
{
printf("KEY4 = %d\r\n",KeyState.value4);
}
KeyState.Press4 = 1;
}
else
{
if(KeyState.value4)
{
KeyState.value4 = 0;
printf("KEY4 = %d\r\n",KeyState.value4);
}
KeyState.Press4 = 0;
}
if(Key5_IN_Read() == 0)//key5
{
KeyState.value5 = 1;
if(!KeyState.Press5)
{
printf("KEY5 = %d\r\n",KeyState.value5);
}
KeyState.Press5 = 1;
}
else
{
if(KeyState.value5)
{
KeyState.value5 = 0;
printf("KEY2 = %d\r\n",KeyState.value5);
}
KeyState.Press5 = 0;
}
if(Key6_IN_Read() == 0)//key6
{
KeyState.value6 = 1;
if(!KeyState.Press6)
{
printf("KEY6 = %d\r\n",KeyState.value6);
}
KeyState.Press6 = 1;
}
else
{
if(KeyState.value6)
{
KeyState.value6 = 0;
printf("KEY2 = %d\r\n",KeyState.value6);
}
KeyState.Press6 = 0;
}
if(Key7_IN_Read() == 0)//key7
{
KeyState.value7 = 1;
if(!KeyState.Press7)
{
printf("KEY7 = %d\r\n",KeyState.value7);
}
KeyState.Press7 = 1;
}
else
{
if(KeyState.value7)
{
KeyState.value7 = 0;
printf("KEY2 = %d\r\n",KeyState.value7);
}
KeyState.Press7 = 0;
}
if(Key8_IN_Read() == 0)//key8
{
KeyState.value8 = 1;
if(!KeyState.Press8)
{
printf("KEY8 = %d\r\n",KeyState.value8);
}
KeyState.Press8 = 1;
}
else
{
if(KeyState.value8)
{
KeyState.value8 = 0;
printf("KEY2 = %d\r\n",KeyState.value8);
}
KeyState.Press8 = 0;
}
}
4.6 模式切换
if(KeyMode1_IN_Read() == 0)//keyMode1
{
if(!KeyState.Mode1_Press)
{
show_mode = 1;
ADC_FLAG = 2;
printf("\r\nkeyMode1\r\n");
}
KeyState.Mode1_Press = 1;
}
else
{
KeyState.Mode1_Press = 0;
}
if(KeyMode2_IN_Read() == 0)//keyMode2
{
if(!KeyState.Mode2_Press)
{
show_mode = 2;
DAC_FLAG = 1;
printf("\r\nkeyMode2\r\n");
}
KeyState.Mode2_Press = 1;
}
else
{
KeyState.Mode2_Press = 0;
}
if(KeyMode3_IN_Read() == 0)//keyMode3
{
if(!KeyState.Mode3_Press)
{
show_mode = 3;
KEY_FLAG = 1;
printf("\r\nkeyMode3\r\n");
}
KeyState.Mode3_Press = 1;
}
else
{
KeyState.Mode3_Press = 0;
}
二、总结
今天主要讲了基于STM32的数据采集系统的Proteus仿真。
感谢你的观看!