- /*
- * DS18B20 input to port D4
- * 8 digit 7-segment LED display with MAX7219 controller chip
- * DIN <-> C6 (MOSI)
- * CS <-> D2 (slave select)
- * CLK <-> C5 (clock)
- */
- #include <stdint.h>
- #include "stm8.h"
- /* 1-Wire (DS18B20 data) pin */
- #define OW_PORT PA
- #define OW_PIN PIN3
- /* Simple busy loop delay */
- void delay(unsigned long count) {
- while (count--)
- nop();
- }
- /* For LED-display */
- void setup_spi() {
- // SPI port setup: MISO is pullup in, MOSI & SCK are push-pull out
- PC_DDR |= PIN5 | PIN6; // clock and MOSI
- PC_CR1 |= PIN5 | PIN6 | PIN7;
- // CS/SS (PD2) as output
- PD_DDR |= PIN2;
- PD_CR1 |= PIN2;
- PD_ODR |= PIN2; // CS high
- // SPI registers: First reset everything
- SPI_CR1 = 0;
- SPI_CR2 = 0;
- // SPI_CR1 LSBFIRST=0 (MSB is transmitted first)
- SPI_CR1 &= ~SPI_CR1_LSBFIRST;
- // Baud Rate Control: 0b111 = fmaster / 256 (62,500 baud)
- SPI_CR1 |= SPI_CR1_BR(0b111);
- // SPI_CR1 CPOL=0 (Clock Phase, The first clock transition is the first data capture edge)
- SPI_CR1 &= ~SPI_CR1_CPOL;
- // SPI_CR1 CPHA=0 (Clock Polarity, SCK to 0 when idle)
- SPI_CR1 &= ~SPI_CR1_CPHA;
- SPI_CR2 |= SPI_CR2_SSM; // bit 1 SSM=1 Software slave management, enabled
- SPI_CR2 |= SPI_CR2_SSI; // bit 0 SSI=1 Internal slave select, Master mode
- SPI_CR1 |= SPI_CR1_MSTR; // CR1 bit 2 MSTR = 1, Master configuration.
- }
- uint8_t SPIOut(uint8_t data) {
- SPI_CR1 |= SPI_CR1_MSTR;; // MSTR = 1, Master device.
- SPI_CR1 |= SPI_CR1_SPE; // SPE, SPI Enable, Peripheral enabled
- SPI_DR = data;
- while (SPI_SR & SPI_SR_BSY); // SPI is busy in communication or Tx buffer is not empty
- SPI_CR1 &= ~SPI_CR1_SPE; // Disable SPI
- data = SPI_DR;
- return data; // Not yet used.
- }
- void output_max(uint8_t address, uint8_t data) {
- PD_ODR &= ~PIN2; // CS low
- SPIOut(address);
- SPIOut(data);
- PD_ODR |= PIN2; // CS high
- }
- void init_max7219() {
- uint8_t i;
- output_max(0x0f, 0x00); //display test register - test mode off
- output_max(0x0c, 0x01); //shutdown register - normal operation
- output_max(0x0b, 0x07); //scan limit register - display digits 0 thru 7
- output_max(0x0a, 0x01); //intensity register (1 = 3/32 on. 0xf is max)
- output_max(0x09, 0xff); //decode mode register - CodeB decode all digits
- // Blank all digits
- for (i=1; i <= 8; i++) {
- output_max(i, 0xf);
- }
- }
- void display_number_dot(uint32_t number, uint8_t dot_pos, uint8_t is_negative) {
- uint8_t pos=1;
- if (number == 0)
- output_max(pos++, 0);
- while (number > 0 || dot_pos >= pos) {
- uint8_t digit = number % 10;
- if (pos == dot_pos) {
- digit = digit | 0x80;
- }
- output_max(pos++, digit);
- number /= 10;
- }
- if (is_negative) {
- output_max(pos++, 0xa);
- }
- // clear rest of digits
- while (pos <= 8) {
- output_max(pos++, 0xf);
- }
- }
- /********************** OneWire/DS18B20 routines ***************************/
- void delay_us(uint16_t i) {
- if (i < 9) { // FIXME: Really ugly
- nop();
- return;
- }
- TIM2_CNTRH = 0;
- TIM2_CNTRL = 0;
- TIM2_EGR = 0x01; // Update Generation
- while(1) {
- volatile uint16_t counter = (((TIM2_CNTRH) << 8) | TIM2_CNTRL);
- if (i-6 < counter)
- return;
- }
- }
- #define OW_INPUT_MODE() PORT(OW_PORT,DDR) &= ~OW_PIN
- #define OW_OUTPUT_MODE() PORT(OW_PORT,DDR) |= OW_PIN
- #define OW_LOW() PORT(OW_PORT,ODR) &= ~OW_PIN
- #define OW_HIGH() PORT(OW_PORT,ODR) |= OW_PIN
- #define OW_READ() (PORT(OW_PORT,IDR) & OW_PIN)
- void ow_pull_low(unsigned int us) {
- OW_OUTPUT_MODE();
- OW_LOW();
- delay_us(us);
- OW_INPUT_MODE();
- }
- void ow_write_byte(uint8_t out) {
- uint8_t i;
- for (i=0; i < 8; i++) {
- if ( out & ((uint8_t)1<<i) ) {
- // write 1
- ow_pull_low(1);
- delay_us(60);
- } else {
- // write 0
- ow_pull_low(60);
- delay_us(1);
- }
- }
- }
- uint8_t ow_read_byte() {
- uint8_t val = 0;
- uint8_t i;
- for (i=0; i < 8; i++) {
- ow_pull_low(1);
- delay_us(5);
- if (OW_READ()) {
- val |= ((uint8_t)1<<i);
- }
- delay_us(55);
- }
- return val;
- }
- unsigned int ow_init() {
- uint8_t input;
- ow_pull_low(480);
- delay_us(60);
- input = !OW_READ();
- delay_us(420);
- return input;
- }
- unsigned int ow_convert_temperature() {
- int cycles = 1; // For debugging purposes
- ow_write_byte(0x44); // Convert Temperature
- while (1) {
- ow_pull_low(1);
- delay_us(5);
- if (OW_READ()) {
- return cycles;
- }
- delay_us(55);
- cycles++;
- }
- }
- void display_ds_temperature(uint8_t high, uint8_t low) {
- uint8_t is_negative = 0;
- uint16_t decimals = 0; // 4 decimals (e.g. decimals 625 means 0.0625)
- uint16_t i;
- uint16_t temp = ((int16_t)high << 8) | low;
- if (temp & 0x8000) {
- is_negative = 1;
- temp = (~temp) + 1;
- }
- low = temp & 0x0f;
- temp = temp >> 4;
- // low[3:0] mean values 0.5,0.25,0.125 and 0.0625
- for (i=625; i <= 5000; i=i*2) {
- if (low & 0x01) {
- decimals += i;
- }
- low = low >> 1;
- }
- // Display temperature rounded to one decimal
- display_number_dot((temp*1000 + ((decimals+5)/10) + 50)/100, 2, is_negative);
- }
- void read_ds18b20() {
- uint8_t i;
- uint8_t scratchpad[9];
- if (ow_init()) {
- ow_write_byte(0xcc); // Skip ROM
- ow_convert_temperature();
- ow_init();
- ow_write_byte(0xcc); // Skip ROM
- ow_write_byte(0xbe); // Read Scratchpad
- for (i=0; i<9; i++) {
- scratchpad[i] = ow_read_byte();
- }
- display_ds_temperature(scratchpad[1], scratchpad[0]);
- } else {
- /* DS18B20 was not detected */
- output_max(0x8, 0xa);
- }
- }
- /***************************************************************************/
- int main(void)
- {
- /* Set clock to full speed (16 Mhz) */
- CLK_CKDIVR = 0;
- // Timer setup (for delay_us)
- TIM2_PSCR = 0x4; // Prescaler: to 1MHz
- TIM2_CR1 |= TIM_CR1_CEN; // Start timer
- setup_spi();
- init_max7219();
- while(1) {
- read_ds18b20();
- delay(10000L);
- }
- }
|